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
.assertEqual(s1
.shape(), unsigned(2))
537 self
.assertIsInstance(s1
.shape(), Shape
)
538 s2
= self
.c
.bit_select(self
.s
, 0)
539 self
.assertEqual(s2
.shape(), unsigned(0))
541 def test_stride(self
):
542 s1
= self
.c
.bit_select(self
.s
, 2)
543 self
.assertEqual(s1
.stride
, 1)
545 def test_width_wrong(self
):
546 with self
.assertRaises(TypeError):
547 self
.c
.bit_select(self
.s
, -1)
550 s
= self
.c
.bit_select(self
.s
, 2)
551 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 1)")
554 class WordSelectTestCase(FHDLTestCase
):
557 self
.s
= Signal(range(self
.c
.width
))
559 def test_shape(self
):
560 s1
= self
.c
.word_select(self
.s
, 2)
561 self
.assertEqual(s1
.shape(), unsigned(2))
562 self
.assertIsInstance(s1
.shape(), Shape
)
564 def test_stride(self
):
565 s1
= self
.c
.word_select(self
.s
, 2)
566 self
.assertEqual(s1
.stride
, 2)
568 def test_width_wrong(self
):
569 with self
.assertRaises(TypeError):
570 self
.c
.word_select(self
.s
, 0)
571 with self
.assertRaises(TypeError):
572 self
.c
.word_select(self
.s
, -1)
575 s
= self
.c
.word_select(self
.s
, 2)
576 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 2)")
579 class CatTestCase(FHDLTestCase
):
580 def test_shape(self
):
582 self
.assertEqual(c0
.shape(), unsigned(0))
583 self
.assertIsInstance(c0
.shape(), Shape
)
585 self
.assertEqual(c1
.shape(), unsigned(4))
586 c2
= Cat(Const(10), Const(1))
587 self
.assertEqual(c2
.shape(), unsigned(5))
588 c3
= Cat(Const(10), Const(1), Const(0))
589 self
.assertEqual(c3
.shape(), unsigned(6))
592 c1
= Cat(Const(10), Const(1))
593 self
.assertEqual(repr(c1
), "(cat (const 4'd10) (const 1'd1))")
596 class ReplTestCase(FHDLTestCase
):
597 def test_shape(self
):
598 s1
= Repl(Const(10), 3)
599 self
.assertEqual(s1
.shape(), unsigned(12))
600 self
.assertIsInstance(s1
.shape(), Shape
)
601 s2
= Repl(Const(10), 0)
602 self
.assertEqual(s2
.shape(), unsigned(0))
604 def test_count_wrong(self
):
605 with self
.assertRaises(TypeError):
607 with self
.assertRaises(TypeError):
608 Repl(Const(10), "str")
611 s
= Repl(Const(10), 3)
612 self
.assertEqual(repr(s
), "(repl (const 4'd10) 3)")
615 class ArrayTestCase(FHDLTestCase
):
616 def test_acts_like_array(self
):
618 self
.assertSequenceEqual(a
, [1,2,3])
619 self
.assertEqual(a
[1], 2)
621 self
.assertSequenceEqual(a
, [1,4,3])
623 self
.assertSequenceEqual(a
, [1,3])
625 self
.assertSequenceEqual(a
, [1,2,3])
627 def test_becomes_immutable(self
):
629 s1
= Signal(range(len(a
)))
630 s2
= Signal(range(len(a
)))
633 with self
.assertRaisesRegex(ValueError,
634 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
636 with self
.assertRaisesRegex(ValueError,
637 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
639 with self
.assertRaisesRegex(ValueError,
640 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
645 self
.assertEqual(repr(a
), "(array mutable [1, 2, 3])")
646 s
= Signal(range(len(a
)))
648 self
.assertEqual(repr(a
), "(array [1, 2, 3])")
651 class ArrayProxyTestCase(FHDLTestCase
):
652 def test_index_shape(self
):
653 m
= Array(Array(x
* y
for y
in range(1, 4)) for x
in range(1, 4))
657 self
.assertEqual(v
.shape(), unsigned(4))
659 def test_attr_shape(self
):
660 from collections
import namedtuple
661 pair
= namedtuple("pair", ("p", "n"))
662 a
= Array(pair(i
, -i
) for i
in range(10))
663 s
= Signal(range(len(a
)))
665 self
.assertEqual(v
.p
.shape(), unsigned(4))
666 self
.assertEqual(v
.n
.shape(), signed(6))
672 self
.assertEqual(repr(v
), "(proxy (array [1, 2, 3]) (sig s))")
675 class SignalTestCase(FHDLTestCase
):
676 def test_shape(self
):
678 self
.assertEqual(s1
.shape(), unsigned(1))
679 self
.assertIsInstance(s1
.shape(), Shape
)
681 self
.assertEqual(s2
.shape(), unsigned(2))
682 s3
= Signal(unsigned(2))
683 self
.assertEqual(s3
.shape(), unsigned(2))
684 s4
= Signal(signed(2))
685 self
.assertEqual(s4
.shape(), signed(2))
687 self
.assertEqual(s5
.shape(), unsigned(0))
688 s6
= Signal(range(16))
689 self
.assertEqual(s6
.shape(), unsigned(4))
690 s7
= Signal(range(4, 16))
691 self
.assertEqual(s7
.shape(), unsigned(4))
692 s8
= Signal(range(-4, 16))
693 self
.assertEqual(s8
.shape(), signed(5))
694 s9
= Signal(range(-20, 16))
695 self
.assertEqual(s9
.shape(), signed(6))
696 s10
= Signal(range(0))
697 self
.assertEqual(s10
.shape(), unsigned(0))
698 s11
= Signal(range(1))
699 self
.assertEqual(s11
.shape(), unsigned(1))
701 with warnings
.catch_warnings():
702 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
704 self
.assertEqual(d6
.shape(), unsigned(4))
705 d7
= Signal(min=4, max=16)
706 self
.assertEqual(d7
.shape(), unsigned(4))
707 d8
= Signal(min=-4, max=16)
708 self
.assertEqual(d8
.shape(), signed(5))
709 d9
= Signal(min=-20, max=16)
710 self
.assertEqual(d9
.shape(), signed(6))
712 self
.assertEqual(d10
.shape(), unsigned(0))
714 def test_shape_wrong(self
):
715 with self
.assertRaises(TypeError,
716 msg
="Width must be a non-negative integer, not -10"):
719 def test_min_max_deprecated(self
):
720 with self
.assertWarns(DeprecationWarning,
721 msg
="instead of `Signal(min=0, max=10)`, use `Signal(range(0, 10))`"):
723 with warnings
.catch_warnings():
724 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
725 with self
.assertRaises(ValueError,
726 msg
="Lower bound 10 should be less or equal to higher bound 4"):
727 Signal(min=10, max=4)
728 with self
.assertRaises(ValueError,
729 msg
="Only one of bits/signedness or bounds may be specified"):
734 self
.assertEqual(s1
.name
, "s1")
735 s2
= Signal(name
="sig")
736 self
.assertEqual(s2
.name
, "sig")
738 def test_reset(self
):
739 s1
= Signal(4, reset
=0b111, reset_less
=True)
740 self
.assertEqual(s1
.reset
, 0b111)
741 self
.assertEqual(s1
.reset_less
, True)
743 def test_reset_narrow(self
):
744 with self
.assertWarns(SyntaxWarning,
745 msg
="Reset value 8 requires 4 bits to represent, but the signal only has 3 bits"):
747 with self
.assertWarns(SyntaxWarning,
748 msg
="Reset value 4 requires 4 bits to represent, but the signal only has 3 bits"):
749 Signal(signed(3), reset
=4)
750 with self
.assertWarns(SyntaxWarning,
751 msg
="Reset value -5 requires 4 bits to represent, but the signal only has 3 bits"):
752 Signal(signed(3), reset
=-5)
754 def test_attrs(self
):
756 self
.assertEqual(s1
.attrs
, {})
757 s2
= Signal(attrs
={"no_retiming": True})
758 self
.assertEqual(s2
.attrs
, {"no_retiming": True})
762 self
.assertEqual(repr(s1
), "(sig s1)")
765 s1
= Signal
.like(Signal(4))
766 self
.assertEqual(s1
.shape(), unsigned(4))
767 s2
= Signal
.like(Signal(range(-15, 1)))
768 self
.assertEqual(s2
.shape(), signed(5))
769 s3
= Signal
.like(Signal(4, reset
=0b111, reset_less
=True))
770 self
.assertEqual(s3
.reset
, 0b111)
771 self
.assertEqual(s3
.reset_less
, True)
772 s4
= Signal
.like(Signal(attrs
={"no_retiming": True}))
773 self
.assertEqual(s4
.attrs
, {"no_retiming": True})
774 s5
= Signal
.like(Signal(decoder
=str))
775 self
.assertEqual(s5
.decoder
, str)
777 self
.assertEqual(s6
.shape(), unsigned(4))
778 s7
= [Signal
.like(Signal(4))][0]
779 self
.assertEqual(s7
.name
, "$like")
780 s8
= Signal
.like(s1
, name_suffix
="_ff")
781 self
.assertEqual(s8
.name
, "s1_ff")
783 def test_decoder(self
):
787 s
= Signal(decoder
=Color
)
788 self
.assertEqual(s
.decoder(1), "RED/1")
789 self
.assertEqual(s
.decoder(3), "3")
792 s1
= Signal(UnsignedEnum
)
793 self
.assertEqual(s1
.shape(), unsigned(2))
794 s2
= Signal(SignedEnum
)
795 self
.assertEqual(s2
.shape(), signed(2))
796 self
.assertEqual(s2
.decoder(SignedEnum
.FOO
), "FOO/-1")
799 class ClockSignalTestCase(FHDLTestCase
):
800 def test_domain(self
):
802 self
.assertEqual(s1
.domain
, "sync")
803 s2
= ClockSignal("pix")
804 self
.assertEqual(s2
.domain
, "pix")
806 with self
.assertRaises(TypeError,
807 msg
="Clock domain name must be a string, not 1"):
810 def test_shape(self
):
812 self
.assertEqual(s1
.shape(), unsigned(1))
813 self
.assertIsInstance(s1
.shape(), Shape
)
817 self
.assertEqual(repr(s1
), "(clk sync)")
819 def test_wrong_name_comb(self
):
820 with self
.assertRaises(ValueError,
821 msg
="Domain 'comb' does not have a clock"):
825 class ResetSignalTestCase(FHDLTestCase
):
826 def test_domain(self
):
828 self
.assertEqual(s1
.domain
, "sync")
829 s2
= ResetSignal("pix")
830 self
.assertEqual(s2
.domain
, "pix")
832 with self
.assertRaises(TypeError,
833 msg
="Clock domain name must be a string, not 1"):
836 def test_shape(self
):
838 self
.assertEqual(s1
.shape(), unsigned(1))
839 self
.assertIsInstance(s1
.shape(), Shape
)
843 self
.assertEqual(repr(s1
), "(rst sync)")
845 def test_wrong_name_comb(self
):
846 with self
.assertRaises(ValueError,
847 msg
="Domain 'comb' does not have a reset"):
851 class MockUserValue(UserValue
):
852 def __init__(self
, lowered
):
855 self
.lowered
= lowered
858 self
.lower_count
+= 1
862 class UserValueTestCase(FHDLTestCase
):
863 def test_shape(self
):
864 uv
= MockUserValue(1)
865 self
.assertEqual(uv
.shape(), unsigned(1))
866 self
.assertIsInstance(uv
.shape(), Shape
)
868 self
.assertEqual(uv
.shape(), unsigned(1))
869 self
.assertEqual(uv
.lower_count
, 1)
872 class SampleTestCase(FHDLTestCase
):
873 def test_const(self
):
874 s
= Sample(1, 1, "sync")
875 self
.assertEqual(s
.shape(), unsigned(1))
877 def test_signal(self
):
878 s1
= Sample(Signal(2), 1, "sync")
879 self
.assertEqual(s1
.shape(), unsigned(2))
880 s2
= Sample(ClockSignal(), 1, "sync")
881 s3
= Sample(ResetSignal(), 1, "sync")
883 def test_wrong_value_operator(self
):
884 with self
.assertRaises(TypeError,
885 "Sampled value must be a signal or a constant, not "
886 "(+ (sig $signal) (const 1'd1))"):
887 Sample(Signal() + 1, 1, "sync")
889 def test_wrong_clocks_neg(self
):
890 with self
.assertRaises(ValueError,
891 "Cannot sample a value 1 cycles in the future"):
892 Sample(Signal(), -1, "sync")
894 def test_wrong_domain(self
):
895 with self
.assertRaises(TypeError,
896 "Domain name must be a string or None, not 0"):
897 Sample(Signal(), 1, 0)
900 class InitialTestCase(FHDLTestCase
):
901 def test_initial(self
):
903 self
.assertEqual(i
.shape(), unsigned(1))