4 from ..hdl
.ast
import *
8 class UnsignedEnum(Enum
):
14 class SignedEnum(Enum
):
20 class StringEnum(Enum
):
25 class ShapeTestCase(FHDLTestCase
):
28 self
.assertEqual(s1
.width
, 1)
29 self
.assertEqual(s1
.signed
, False)
30 s2
= Shape(signed
=True)
31 self
.assertEqual(s2
.width
, 1)
32 self
.assertEqual(s2
.signed
, True)
34 self
.assertEqual(s3
.width
, 3)
35 self
.assertEqual(s3
.signed
, True)
37 def test_make_wrong(self
):
38 with self
.assertRaises(TypeError,
39 msg
="Width must be a non-negative integer, not -1"):
43 width
, signed
= Shape()
44 self
.assertEqual(width
, 1)
45 self
.assertEqual(signed
, False)
47 def test_unsigned(self
):
49 self
.assertIsInstance(s1
, Shape
)
50 self
.assertEqual(s1
.width
, 2)
51 self
.assertEqual(s1
.signed
, False)
53 def test_signed(self
):
55 self
.assertIsInstance(s1
, Shape
)
56 self
.assertEqual(s1
.width
, 2)
57 self
.assertEqual(s1
.signed
, True)
59 def test_cast_shape(self
):
60 s1
= Shape
.cast(unsigned(1))
61 self
.assertEqual(s1
.width
, 1)
62 self
.assertEqual(s1
.signed
, False)
63 s2
= Shape
.cast(signed(3))
64 self
.assertEqual(s2
.width
, 3)
65 self
.assertEqual(s2
.signed
, True)
67 def test_cast_int(self
):
69 self
.assertEqual(s1
.width
, 2)
70 self
.assertEqual(s1
.signed
, False)
72 def test_cast_int_wrong(self
):
73 with self
.assertRaises(TypeError,
74 msg
="Width must be a non-negative integer, not -1"):
77 def test_cast_tuple(self
):
78 with warnings
.catch_warnings():
79 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
80 s1
= Shape
.cast((1, True))
81 self
.assertEqual(s1
.width
, 1)
82 self
.assertEqual(s1
.signed
, True)
84 def test_cast_tuple_wrong(self
):
85 with warnings
.catch_warnings():
86 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
87 with self
.assertRaises(TypeError,
88 msg
="Width must be a non-negative integer, not -1"):
89 Shape
.cast((-1, True))
91 def test_cast_range(self
):
92 s1
= Shape
.cast(range(0, 8))
93 self
.assertEqual(s1
.width
, 3)
94 self
.assertEqual(s1
.signed
, False)
95 s2
= Shape
.cast(range(0, 9))
96 self
.assertEqual(s2
.width
, 4)
97 self
.assertEqual(s2
.signed
, False)
98 s3
= Shape
.cast(range(-7, 8))
99 self
.assertEqual(s3
.width
, 4)
100 self
.assertEqual(s3
.signed
, True)
101 s4
= Shape
.cast(range(0, 1))
102 self
.assertEqual(s4
.width
, 1)
103 self
.assertEqual(s4
.signed
, False)
104 s5
= Shape
.cast(range(-1, 0))
105 self
.assertEqual(s5
.width
, 1)
106 self
.assertEqual(s5
.signed
, True)
107 s6
= Shape
.cast(range(0, 0))
108 self
.assertEqual(s6
.width
, 0)
109 self
.assertEqual(s6
.signed
, False)
110 s7
= Shape
.cast(range(-1, -1))
111 self
.assertEqual(s7
.width
, 0)
112 self
.assertEqual(s7
.signed
, True)
114 def test_cast_enum(self
):
115 s1
= Shape
.cast(UnsignedEnum
)
116 self
.assertEqual(s1
.width
, 2)
117 self
.assertEqual(s1
.signed
, False)
118 s2
= Shape
.cast(SignedEnum
)
119 self
.assertEqual(s2
.width
, 2)
120 self
.assertEqual(s2
.signed
, True)
122 def test_cast_enum_bad(self
):
123 with self
.assertRaises(TypeError,
124 msg
="Only enumerations with integer values can be used as value shapes"):
125 Shape
.cast(StringEnum
)
127 def test_cast_bad(self
):
128 with self
.assertRaises(TypeError,
129 msg
="Object 'foo' cannot be used as value shape"):
133 class ValueTestCase(FHDLTestCase
):
135 self
.assertIsInstance(Value
.cast(0), Const
)
136 self
.assertIsInstance(Value
.cast(True), Const
)
138 self
.assertIs(Value
.cast(c
), c
)
139 with self
.assertRaises(TypeError,
140 msg
="Object 'str' cannot be converted to an nMigen value"):
143 def test_cast_enum(self
):
144 e1
= Value
.cast(UnsignedEnum
.FOO
)
145 self
.assertIsInstance(e1
, Const
)
146 self
.assertEqual(e1
.shape(), unsigned(2))
147 e2
= Value
.cast(SignedEnum
.FOO
)
148 self
.assertIsInstance(e2
, Const
)
149 self
.assertEqual(e2
.shape(), signed(2))
151 def test_cast_enum_wrong(self
):
152 with self
.assertRaises(TypeError,
153 msg
="Only enumerations with integer values can be used as value shapes"):
154 Value
.cast(StringEnum
.FOO
)
157 with self
.assertRaises(TypeError,
158 msg
="Attempted to convert nMigen value to boolean"):
163 self
.assertEqual(len(Const(10)), 4)
165 def test_getitem_int(self
):
167 self
.assertIsInstance(s1
, Slice
)
168 self
.assertEqual(s1
.start
, 0)
169 self
.assertEqual(s1
.stop
, 1)
171 self
.assertIsInstance(s2
, Slice
)
172 self
.assertEqual(s2
.start
, 3)
173 self
.assertEqual(s2
.stop
, 4)
174 with self
.assertRaises(IndexError,
175 msg
="Cannot index 5 bits into 4-bit value"):
178 def test_getitem_slice(self
):
180 self
.assertIsInstance(s1
, Slice
)
181 self
.assertEqual(s1
.start
, 1)
182 self
.assertEqual(s1
.stop
, 3)
184 self
.assertIsInstance(s2
, Slice
)
185 self
.assertEqual(s2
.start
, 1)
186 self
.assertEqual(s2
.stop
, 2)
188 self
.assertIsInstance(s3
, Cat
)
189 self
.assertIsInstance(s3
.parts
[0], Slice
)
190 self
.assertEqual(s3
.parts
[0].start
, 0)
191 self
.assertEqual(s3
.parts
[0].stop
, 1)
192 self
.assertIsInstance(s3
.parts
[1], Slice
)
193 self
.assertEqual(s3
.parts
[1].start
, 2)
194 self
.assertEqual(s3
.parts
[1].stop
, 3)
195 self
.assertIsInstance(s3
.parts
[2], Slice
)
196 self
.assertEqual(s3
.parts
[2].start
, 4)
197 self
.assertEqual(s3
.parts
[2].stop
, 5)
199 def test_getitem_wrong(self
):
200 with self
.assertRaises(TypeError,
201 msg
="Cannot index value with 'str'"):
205 class ConstTestCase(FHDLTestCase
):
206 def test_shape(self
):
207 self
.assertEqual(Const(0).shape(), unsigned(1))
208 self
.assertIsInstance(Const(0).shape(), Shape
)
209 self
.assertEqual(Const(1).shape(), unsigned(1))
210 self
.assertEqual(Const(10).shape(), unsigned(4))
211 self
.assertEqual(Const(-10).shape(), signed(5))
213 self
.assertEqual(Const(1, 4).shape(), unsigned(4))
214 self
.assertEqual(Const(-1, 4).shape(), signed(4))
215 self
.assertEqual(Const(1, signed(4)).shape(), signed(4))
216 self
.assertEqual(Const(0, unsigned(0)).shape(), unsigned(0))
218 def test_shape_wrong(self
):
219 with self
.assertRaises(TypeError,
220 msg
="Width must be a non-negative integer, not -1"):
223 def test_normalization(self
):
224 self
.assertEqual(Const(0b10110, signed(5)).value
, -10)
226 def test_value(self
):
227 self
.assertEqual(Const(10).value
, 10)
230 self
.assertEqual(repr(Const(10)), "(const 4'd10)")
231 self
.assertEqual(repr(Const(-10)), "(const 5'sd-10)")
234 with self
.assertRaises(TypeError):
238 class OperatorTestCase(FHDLTestCase
):
240 v
= Const(0, 4).bool()
241 self
.assertEqual(repr(v
), "(b (const 4'd0))")
242 self
.assertEqual(v
.shape(), unsigned(1))
244 def test_invert(self
):
246 self
.assertEqual(repr(v
), "(~ (const 4'd0))")
247 self
.assertEqual(v
.shape(), unsigned(4))
250 v1
= -Const(0, unsigned(4))
251 self
.assertEqual(repr(v1
), "(- (const 4'd0))")
252 self
.assertEqual(v1
.shape(), signed(5))
253 v2
= -Const(0, signed(4))
254 self
.assertEqual(repr(v2
), "(- (const 4'sd0))")
255 self
.assertEqual(v2
.shape(), signed(4))
258 v1
= Const(0, unsigned(4)) + Const(0, unsigned(6))
259 self
.assertEqual(repr(v1
), "(+ (const 4'd0) (const 6'd0))")
260 self
.assertEqual(v1
.shape(), unsigned(7))
261 v2
= Const(0, signed(4)) + Const(0, signed(6))
262 self
.assertEqual(v2
.shape(), signed(7))
263 v3
= Const(0, signed(4)) + Const(0, unsigned(4))
264 self
.assertEqual(v3
.shape(), signed(6))
265 v4
= Const(0, unsigned(4)) + Const(0, signed(4))
266 self
.assertEqual(v4
.shape(), signed(6))
267 v5
= 10 + Const(0, 4)
268 self
.assertEqual(v5
.shape(), unsigned(5))
271 v1
= Const(0, unsigned(4)) - Const(0, unsigned(6))
272 self
.assertEqual(repr(v1
), "(- (const 4'd0) (const 6'd0))")
273 self
.assertEqual(v1
.shape(), unsigned(7))
274 v2
= Const(0, signed(4)) - Const(0, signed(6))
275 self
.assertEqual(v2
.shape(), signed(7))
276 v3
= Const(0, signed(4)) - Const(0, unsigned(4))
277 self
.assertEqual(v3
.shape(), signed(6))
278 v4
= Const(0, unsigned(4)) - Const(0, signed(4))
279 self
.assertEqual(v4
.shape(), signed(6))
280 v5
= 10 - Const(0, 4)
281 self
.assertEqual(v5
.shape(), unsigned(5))
284 v1
= Const(0, unsigned(4)) * Const(0, unsigned(6))
285 self
.assertEqual(repr(v1
), "(* (const 4'd0) (const 6'd0))")
286 self
.assertEqual(v1
.shape(), unsigned(10))
287 v2
= Const(0, signed(4)) * Const(0, signed(6))
288 self
.assertEqual(v2
.shape(), signed(10))
289 v3
= Const(0, signed(4)) * Const(0, unsigned(4))
290 self
.assertEqual(v3
.shape(), signed(8))
291 v5
= 10 * Const(0, 4)
292 self
.assertEqual(v5
.shape(), unsigned(8))
295 v1
= Const(0, unsigned(4)) % Const(0, unsigned(6))
296 self
.assertEqual(repr(v1
), "(% (const 4'd0) (const 6'd0))")
297 self
.assertEqual(v1
.shape(), unsigned(4))
298 v3
= Const(0, signed(4)) % Const(0, unsigned(4))
299 self
.assertEqual(v3
.shape(), signed(4))
300 v5
= 10 % Const(0, 4)
301 self
.assertEqual(v5
.shape(), unsigned(4))
303 def test_mod_wrong(self
):
304 with self
.assertRaises(NotImplementedError,
305 msg
="Division by a signed value is not supported"):
306 Const(0, signed(4)) % Const(0, signed(6))
308 def test_floordiv(self
):
309 v1
= Const(0, unsigned(4)) // Const(0, unsigned(6))
310 self
.assertEqual(repr(v1
), "(// (const 4'd0) (const 6'd0))")
311 self
.assertEqual(v1
.shape(), unsigned(4))
312 v3
= Const(0, signed(4)) // Const(0, unsigned(4))
313 self
.assertEqual(v3
.shape(), signed(4))
314 v5
= 10 // Const(0, 4)
315 self
.assertEqual(v5
.shape(), unsigned(4))
317 def test_floordiv_wrong(self
):
318 with self
.assertRaises(NotImplementedError,
319 msg
="Division by a signed value is not supported"):
320 Const(0, signed(4)) // Const(0, signed(6))
323 v1
= Const(0, unsigned(4)) & Const(0, unsigned(6))
324 self
.assertEqual(repr(v1
), "(& (const 4'd0) (const 6'd0))")
325 self
.assertEqual(v1
.shape(), unsigned(6))
326 v2
= Const(0, signed(4)) & Const(0, signed(6))
327 self
.assertEqual(v2
.shape(), signed(6))
328 v3
= Const(0, signed(4)) & Const(0, unsigned(4))
329 self
.assertEqual(v3
.shape(), signed(5))
330 v4
= Const(0, unsigned(4)) & Const(0, signed(4))
331 self
.assertEqual(v4
.shape(), signed(5))
332 v5
= 10 & Const(0, 4)
333 self
.assertEqual(v5
.shape(), unsigned(4))
336 v1
= Const(0, unsigned(4)) |
Const(0, unsigned(6))
337 self
.assertEqual(repr(v1
), "(| (const 4'd0) (const 6'd0))")
338 self
.assertEqual(v1
.shape(), unsigned(6))
339 v2
= Const(0, signed(4)) |
Const(0, signed(6))
340 self
.assertEqual(v2
.shape(), signed(6))
341 v3
= Const(0, signed(4)) |
Const(0, unsigned(4))
342 self
.assertEqual(v3
.shape(), signed(5))
343 v4
= Const(0, unsigned(4)) |
Const(0, signed(4))
344 self
.assertEqual(v4
.shape(), signed(5))
345 v5
= 10 |
Const(0, 4)
346 self
.assertEqual(v5
.shape(), unsigned(4))
349 v1
= Const(0, unsigned(4)) ^
Const(0, unsigned(6))
350 self
.assertEqual(repr(v1
), "(^ (const 4'd0) (const 6'd0))")
351 self
.assertEqual(v1
.shape(), unsigned(6))
352 v2
= Const(0, signed(4)) ^
Const(0, signed(6))
353 self
.assertEqual(v2
.shape(), signed(6))
354 v3
= Const(0, signed(4)) ^
Const(0, unsigned(4))
355 self
.assertEqual(v3
.shape(), signed(5))
356 v4
= Const(0, unsigned(4)) ^
Const(0, signed(4))
357 self
.assertEqual(v4
.shape(), signed(5))
358 v5
= 10 ^
Const(0, 4)
359 self
.assertEqual(v5
.shape(), unsigned(4))
362 v1
= Const(1, 4) << Const(4)
363 self
.assertEqual(repr(v1
), "(<< (const 4'd1) (const 3'd4))")
364 self
.assertEqual(v1
.shape(), unsigned(11))
365 v2
= Const(1, 4) << Const(-3)
366 self
.assertEqual(v2
.shape(), unsigned(7))
369 v1
= Const(1, 4) >> Const(4)
370 self
.assertEqual(repr(v1
), "(>> (const 4'd1) (const 3'd4))")
371 self
.assertEqual(v1
.shape(), unsigned(4))
372 v2
= Const(1, 4) >> Const(-3)
373 self
.assertEqual(v2
.shape(), unsigned(8))
376 v
= Const(0, 4) < Const(0, 6)
377 self
.assertEqual(repr(v
), "(< (const 4'd0) (const 6'd0))")
378 self
.assertEqual(v
.shape(), unsigned(1))
381 v
= Const(0, 4) <= Const(0, 6)
382 self
.assertEqual(repr(v
), "(<= (const 4'd0) (const 6'd0))")
383 self
.assertEqual(v
.shape(), unsigned(1))
386 v
= Const(0, 4) > Const(0, 6)
387 self
.assertEqual(repr(v
), "(> (const 4'd0) (const 6'd0))")
388 self
.assertEqual(v
.shape(), unsigned(1))
391 v
= Const(0, 4) >= Const(0, 6)
392 self
.assertEqual(repr(v
), "(>= (const 4'd0) (const 6'd0))")
393 self
.assertEqual(v
.shape(), unsigned(1))
396 v
= Const(0, 4) == Const(0, 6)
397 self
.assertEqual(repr(v
), "(== (const 4'd0) (const 6'd0))")
398 self
.assertEqual(v
.shape(), unsigned(1))
401 v
= Const(0, 4) != Const(0, 6)
402 self
.assertEqual(repr(v
), "(!= (const 4'd0) (const 6'd0))")
403 self
.assertEqual(v
.shape(), unsigned(1))
407 v1
= Mux(s
, Const(0, unsigned(4)), Const(0, unsigned(6)))
408 self
.assertEqual(repr(v1
), "(m (const 1'd0) (const 4'd0) (const 6'd0))")
409 self
.assertEqual(v1
.shape(), unsigned(6))
410 v2
= Mux(s
, Const(0, signed(4)), Const(0, signed(6)))
411 self
.assertEqual(v2
.shape(), signed(6))
412 v3
= Mux(s
, Const(0, signed(4)), Const(0, unsigned(4)))
413 self
.assertEqual(v3
.shape(), signed(5))
414 v4
= Mux(s
, Const(0, unsigned(4)), Const(0, signed(4)))
415 self
.assertEqual(v4
.shape(), signed(5))
417 def test_mux_wide(self
):
419 v
= Mux(s
, Const(0, unsigned(4)), Const(0, unsigned(6)))
420 self
.assertEqual(repr(v
), "(m (b (const 3'd4)) (const 4'd0) (const 6'd0))")
422 def test_mux_bool(self
):
423 v
= Mux(True, Const(0), Const(0))
424 self
.assertEqual(repr(v
), "(m (const 1'd1) (const 1'd0) (const 1'd0))")
428 self
.assertEqual(repr(v
), "(b (const 1'd0))")
429 self
.assertEqual(v
.shape(), unsigned(1))
432 v
= Const(0b101).any()
433 self
.assertEqual(repr(v
), "(r| (const 3'd5))")
436 v
= Const(0b101).all()
437 self
.assertEqual(repr(v
), "(r& (const 3'd5))")
440 v
= Const(0b101).xor()
441 self
.assertEqual(repr(v
), "(r^ (const 3'd5))")
443 def test_matches(self
):
445 self
.assertRepr(s
.matches(), "(const 1'd0)")
446 self
.assertRepr(s
.matches(1), """
447 (== (sig s) (const 1'd1))
449 self
.assertRepr(s
.matches(0, 1), """
450 (r| (cat (== (sig s) (const 1'd0)) (== (sig s) (const 1'd1))))
452 self
.assertRepr(s
.matches("10--"), """
453 (== (& (sig s) (const 4'd12)) (const 4'd8))
456 def test_matches_enum(self
):
457 s
= Signal(SignedEnum
)
458 self
.assertRepr(s
.matches(SignedEnum
.FOO
), """
459 (== (sig s) (const 1'sd-1))
462 def test_matches_width_wrong(self
):
464 with self
.assertRaises(SyntaxError,
465 msg
="Match pattern '--' must have the same width as match value (which is 4)"):
467 with self
.assertWarns(SyntaxWarning,
468 msg
="Match pattern '10110' is wider than match value (which has width 4); "
469 "comparison will never be true"):
472 def test_matches_bits_wrong(self
):
474 with self
.assertRaises(SyntaxError,
475 msg
="Match pattern 'abc' must consist of 0, 1, and - (don't care) bits"):
478 def test_matches_pattern_wrong(self
):
480 with self
.assertRaises(SyntaxError,
481 msg
="Match pattern must be an integer, a string, or an enumeration, not 1.0"):
485 with self
.assertRaises(TypeError):
486 hash(Const(0) + Const(0))
489 class SliceTestCase(FHDLTestCase
):
490 def test_shape(self
):
492 self
.assertEqual(s1
.shape(), unsigned(1))
493 self
.assertIsInstance(s1
.shape(), Shape
)
495 self
.assertEqual(s2
.shape(), unsigned(2))
497 def test_start_end_negative(self
):
500 self
.assertEqual((s1
.start
, s1
.stop
), (0, 7))
501 s1
= Slice(c
, -4, -1)
502 self
.assertEqual((s1
.start
, s1
.stop
), (4, 7))
504 def test_start_end_wrong(self
):
505 with self
.assertRaises(TypeError,
506 msg
="Slice start must be an integer, not 'x'"):
508 with self
.assertRaises(TypeError,
509 msg
="Slice stop must be an integer, not 'x'"):
512 def test_start_end_out_of_range(self
):
514 with self
.assertRaises(IndexError,
515 msg
="Cannot start slice 10 bits into 8-bit value"):
517 with self
.assertRaises(IndexError,
518 msg
="Cannot stop slice 12 bits into 8-bit value"):
520 with self
.assertRaises(IndexError,
521 msg
="Slice start 4 must be less than slice stop 2"):
526 self
.assertEqual(repr(s1
), "(slice (const 4'd10) 2:3)")
529 class BitSelectTestCase(FHDLTestCase
):
532 self
.s
= Signal(range(self
.c
.width
))
534 def test_shape(self
):
535 s1
= self
.c
.bit_select(self
.s
, 2)
536 self
.assertIsInstance(s1
, Part
)
537 self
.assertEqual(s1
.shape(), unsigned(2))
538 self
.assertIsInstance(s1
.shape(), Shape
)
539 s2
= self
.c
.bit_select(self
.s
, 0)
540 self
.assertIsInstance(s2
, Part
)
541 self
.assertEqual(s2
.shape(), unsigned(0))
543 def test_stride(self
):
544 s1
= self
.c
.bit_select(self
.s
, 2)
545 self
.assertIsInstance(s1
, Part
)
546 self
.assertEqual(s1
.stride
, 1)
548 def test_const(self
):
549 s1
= self
.c
.bit_select(1, 2)
550 self
.assertIsInstance(s1
, Slice
)
551 self
.assertRepr(s1
, """(slice (const 8'd0) 1:3)""")
553 def test_width_wrong(self
):
554 with self
.assertRaises(TypeError):
555 self
.c
.bit_select(self
.s
, -1)
558 s
= self
.c
.bit_select(self
.s
, 2)
559 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 1)")
562 class WordSelectTestCase(FHDLTestCase
):
565 self
.s
= Signal(range(self
.c
.width
))
567 def test_shape(self
):
568 s1
= self
.c
.word_select(self
.s
, 2)
569 self
.assertIsInstance(s1
, Part
)
570 self
.assertEqual(s1
.shape(), unsigned(2))
571 self
.assertIsInstance(s1
.shape(), Shape
)
573 def test_stride(self
):
574 s1
= self
.c
.word_select(self
.s
, 2)
575 self
.assertIsInstance(s1
, Part
)
576 self
.assertEqual(s1
.stride
, 2)
578 def test_const(self
):
579 s1
= self
.c
.word_select(1, 2)
580 self
.assertIsInstance(s1
, Slice
)
581 self
.assertRepr(s1
, """(slice (const 8'd0) 2:4)""")
583 def test_width_wrong(self
):
584 with self
.assertRaises(TypeError):
585 self
.c
.word_select(self
.s
, 0)
586 with self
.assertRaises(TypeError):
587 self
.c
.word_select(self
.s
, -1)
590 s
= self
.c
.word_select(self
.s
, 2)
591 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 2)")
594 class CatTestCase(FHDLTestCase
):
595 def test_shape(self
):
597 self
.assertEqual(c0
.shape(), unsigned(0))
598 self
.assertIsInstance(c0
.shape(), Shape
)
600 self
.assertEqual(c1
.shape(), unsigned(4))
601 c2
= Cat(Const(10), Const(1))
602 self
.assertEqual(c2
.shape(), unsigned(5))
603 c3
= Cat(Const(10), Const(1), Const(0))
604 self
.assertEqual(c3
.shape(), unsigned(6))
607 c1
= Cat(Const(10), Const(1))
608 self
.assertEqual(repr(c1
), "(cat (const 4'd10) (const 1'd1))")
611 class ReplTestCase(FHDLTestCase
):
612 def test_shape(self
):
613 s1
= Repl(Const(10), 3)
614 self
.assertEqual(s1
.shape(), unsigned(12))
615 self
.assertIsInstance(s1
.shape(), Shape
)
616 s2
= Repl(Const(10), 0)
617 self
.assertEqual(s2
.shape(), unsigned(0))
619 def test_count_wrong(self
):
620 with self
.assertRaises(TypeError):
622 with self
.assertRaises(TypeError):
623 Repl(Const(10), "str")
626 s
= Repl(Const(10), 3)
627 self
.assertEqual(repr(s
), "(repl (const 4'd10) 3)")
630 class ArrayTestCase(FHDLTestCase
):
631 def test_acts_like_array(self
):
633 self
.assertSequenceEqual(a
, [1,2,3])
634 self
.assertEqual(a
[1], 2)
636 self
.assertSequenceEqual(a
, [1,4,3])
638 self
.assertSequenceEqual(a
, [1,3])
640 self
.assertSequenceEqual(a
, [1,2,3])
642 def test_becomes_immutable(self
):
644 s1
= Signal(range(len(a
)))
645 s2
= Signal(range(len(a
)))
648 with self
.assertRaisesRegex(ValueError,
649 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
651 with self
.assertRaisesRegex(ValueError,
652 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
654 with self
.assertRaisesRegex(ValueError,
655 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
660 self
.assertEqual(repr(a
), "(array mutable [1, 2, 3])")
661 s
= Signal(range(len(a
)))
663 self
.assertEqual(repr(a
), "(array [1, 2, 3])")
666 class ArrayProxyTestCase(FHDLTestCase
):
667 def test_index_shape(self
):
668 m
= Array(Array(x
* y
for y
in range(1, 4)) for x
in range(1, 4))
672 self
.assertEqual(v
.shape(), unsigned(4))
674 def test_attr_shape(self
):
675 from collections
import namedtuple
676 pair
= namedtuple("pair", ("p", "n"))
677 a
= Array(pair(i
, -i
) for i
in range(10))
678 s
= Signal(range(len(a
)))
680 self
.assertEqual(v
.p
.shape(), unsigned(4))
681 self
.assertEqual(v
.n
.shape(), signed(6))
687 self
.assertEqual(repr(v
), "(proxy (array [1, 2, 3]) (sig s))")
690 class SignalTestCase(FHDLTestCase
):
691 def test_shape(self
):
693 self
.assertEqual(s1
.shape(), unsigned(1))
694 self
.assertIsInstance(s1
.shape(), Shape
)
696 self
.assertEqual(s2
.shape(), unsigned(2))
697 s3
= Signal(unsigned(2))
698 self
.assertEqual(s3
.shape(), unsigned(2))
699 s4
= Signal(signed(2))
700 self
.assertEqual(s4
.shape(), signed(2))
702 self
.assertEqual(s5
.shape(), unsigned(0))
703 s6
= Signal(range(16))
704 self
.assertEqual(s6
.shape(), unsigned(4))
705 s7
= Signal(range(4, 16))
706 self
.assertEqual(s7
.shape(), unsigned(4))
707 s8
= Signal(range(-4, 16))
708 self
.assertEqual(s8
.shape(), signed(5))
709 s9
= Signal(range(-20, 16))
710 self
.assertEqual(s9
.shape(), signed(6))
711 s10
= Signal(range(0))
712 self
.assertEqual(s10
.shape(), unsigned(0))
713 s11
= Signal(range(1))
714 self
.assertEqual(s11
.shape(), unsigned(1))
716 with warnings
.catch_warnings():
717 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
719 self
.assertEqual(d6
.shape(), unsigned(4))
720 d7
= Signal(min=4, max=16)
721 self
.assertEqual(d7
.shape(), unsigned(4))
722 d8
= Signal(min=-4, max=16)
723 self
.assertEqual(d8
.shape(), signed(5))
724 d9
= Signal(min=-20, max=16)
725 self
.assertEqual(d9
.shape(), signed(6))
727 self
.assertEqual(d10
.shape(), unsigned(0))
729 def test_shape_wrong(self
):
730 with self
.assertRaises(TypeError,
731 msg
="Width must be a non-negative integer, not -10"):
734 def test_min_max_deprecated(self
):
735 with self
.assertWarns(DeprecationWarning,
736 msg
="instead of `Signal(min=0, max=10)`, use `Signal(range(0, 10))`"):
738 with warnings
.catch_warnings():
739 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
740 with self
.assertRaises(ValueError,
741 msg
="Lower bound 10 should be less or equal to higher bound 4"):
742 Signal(min=10, max=4)
743 with self
.assertRaises(ValueError,
744 msg
="Only one of bits/signedness or bounds may be specified"):
749 self
.assertEqual(s1
.name
, "s1")
750 s2
= Signal(name
="sig")
751 self
.assertEqual(s2
.name
, "sig")
753 def test_reset(self
):
754 s1
= Signal(4, reset
=0b111, reset_less
=True)
755 self
.assertEqual(s1
.reset
, 0b111)
756 self
.assertEqual(s1
.reset_less
, True)
758 def test_reset_narrow(self
):
759 with self
.assertWarns(SyntaxWarning,
760 msg
="Reset value 8 requires 4 bits to represent, but the signal only has 3 bits"):
762 with self
.assertWarns(SyntaxWarning,
763 msg
="Reset value 4 requires 4 bits to represent, but the signal only has 3 bits"):
764 Signal(signed(3), reset
=4)
765 with self
.assertWarns(SyntaxWarning,
766 msg
="Reset value -5 requires 4 bits to represent, but the signal only has 3 bits"):
767 Signal(signed(3), reset
=-5)
769 def test_attrs(self
):
771 self
.assertEqual(s1
.attrs
, {})
772 s2
= Signal(attrs
={"no_retiming": True})
773 self
.assertEqual(s2
.attrs
, {"no_retiming": True})
777 self
.assertEqual(repr(s1
), "(sig s1)")
780 s1
= Signal
.like(Signal(4))
781 self
.assertEqual(s1
.shape(), unsigned(4))
782 s2
= Signal
.like(Signal(range(-15, 1)))
783 self
.assertEqual(s2
.shape(), signed(5))
784 s3
= Signal
.like(Signal(4, reset
=0b111, reset_less
=True))
785 self
.assertEqual(s3
.reset
, 0b111)
786 self
.assertEqual(s3
.reset_less
, True)
787 s4
= Signal
.like(Signal(attrs
={"no_retiming": True}))
788 self
.assertEqual(s4
.attrs
, {"no_retiming": True})
789 s5
= Signal
.like(Signal(decoder
=str))
790 self
.assertEqual(s5
.decoder
, str)
792 self
.assertEqual(s6
.shape(), unsigned(4))
793 s7
= [Signal
.like(Signal(4))][0]
794 self
.assertEqual(s7
.name
, "$like")
795 s8
= Signal
.like(s1
, name_suffix
="_ff")
796 self
.assertEqual(s8
.name
, "s1_ff")
798 def test_decoder(self
):
802 s
= Signal(decoder
=Color
)
803 self
.assertEqual(s
.decoder(1), "RED/1")
804 self
.assertEqual(s
.decoder(3), "3")
807 s1
= Signal(UnsignedEnum
)
808 self
.assertEqual(s1
.shape(), unsigned(2))
809 s2
= Signal(SignedEnum
)
810 self
.assertEqual(s2
.shape(), signed(2))
811 self
.assertEqual(s2
.decoder(SignedEnum
.FOO
), "FOO/-1")
814 class ClockSignalTestCase(FHDLTestCase
):
815 def test_domain(self
):
817 self
.assertEqual(s1
.domain
, "sync")
818 s2
= ClockSignal("pix")
819 self
.assertEqual(s2
.domain
, "pix")
821 with self
.assertRaises(TypeError,
822 msg
="Clock domain name must be a string, not 1"):
825 def test_shape(self
):
827 self
.assertEqual(s1
.shape(), unsigned(1))
828 self
.assertIsInstance(s1
.shape(), Shape
)
832 self
.assertEqual(repr(s1
), "(clk sync)")
834 def test_wrong_name_comb(self
):
835 with self
.assertRaises(ValueError,
836 msg
="Domain 'comb' does not have a clock"):
840 class ResetSignalTestCase(FHDLTestCase
):
841 def test_domain(self
):
843 self
.assertEqual(s1
.domain
, "sync")
844 s2
= ResetSignal("pix")
845 self
.assertEqual(s2
.domain
, "pix")
847 with self
.assertRaises(TypeError,
848 msg
="Clock domain name must be a string, not 1"):
851 def test_shape(self
):
853 self
.assertEqual(s1
.shape(), unsigned(1))
854 self
.assertIsInstance(s1
.shape(), Shape
)
858 self
.assertEqual(repr(s1
), "(rst sync)")
860 def test_wrong_name_comb(self
):
861 with self
.assertRaises(ValueError,
862 msg
="Domain 'comb' does not have a reset"):
866 class MockUserValue(UserValue
):
867 def __init__(self
, lowered
):
870 self
.lowered
= lowered
873 self
.lower_count
+= 1
877 class UserValueTestCase(FHDLTestCase
):
878 def test_shape(self
):
879 uv
= MockUserValue(1)
880 self
.assertEqual(uv
.shape(), unsigned(1))
881 self
.assertIsInstance(uv
.shape(), Shape
)
883 self
.assertEqual(uv
.shape(), unsigned(1))
884 self
.assertEqual(uv
.lower_count
, 1)
887 class SampleTestCase(FHDLTestCase
):
888 def test_const(self
):
889 s
= Sample(1, 1, "sync")
890 self
.assertEqual(s
.shape(), unsigned(1))
892 def test_signal(self
):
893 s1
= Sample(Signal(2), 1, "sync")
894 self
.assertEqual(s1
.shape(), unsigned(2))
895 s2
= Sample(ClockSignal(), 1, "sync")
896 s3
= Sample(ResetSignal(), 1, "sync")
898 def test_wrong_value_operator(self
):
899 with self
.assertRaises(TypeError,
900 "Sampled value must be a signal or a constant, not "
901 "(+ (sig $signal) (const 1'd1))"):
902 Sample(Signal() + 1, 1, "sync")
904 def test_wrong_clocks_neg(self
):
905 with self
.assertRaises(ValueError,
906 "Cannot sample a value 1 cycles in the future"):
907 Sample(Signal(), -1, "sync")
909 def test_wrong_domain(self
):
910 with self
.assertRaises(TypeError,
911 "Domain name must be a string or None, not 0"):
912 Sample(Signal(), 1, 0)
915 class InitialTestCase(FHDLTestCase
):
916 def test_initial(self
):
918 self
.assertEqual(i
.shape(), unsigned(1))