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))
249 def test_as_unsigned(self
):
250 v
= Const(-1, signed(4)).as_unsigned()
251 self
.assertEqual(repr(v
), "(u (const 4'sd-1))")
252 self
.assertEqual(v
.shape(), unsigned(4))
254 def test_as_signed(self
):
255 v
= Const(1, unsigned(4)).as_signed()
256 self
.assertEqual(repr(v
), "(s (const 4'd1))")
257 self
.assertEqual(v
.shape(), signed(4))
260 v1
= -Const(0, unsigned(4))
261 self
.assertEqual(repr(v1
), "(- (const 4'd0))")
262 self
.assertEqual(v1
.shape(), signed(5))
263 v2
= -Const(0, signed(4))
264 self
.assertEqual(repr(v2
), "(- (const 4'sd0))")
265 self
.assertEqual(v2
.shape(), signed(5))
268 v1
= Const(0, unsigned(4)) + Const(0, unsigned(6))
269 self
.assertEqual(repr(v1
), "(+ (const 4'd0) (const 6'd0))")
270 self
.assertEqual(v1
.shape(), unsigned(7))
271 v2
= Const(0, signed(4)) + Const(0, signed(6))
272 self
.assertEqual(v2
.shape(), signed(7))
273 v3
= Const(0, signed(4)) + Const(0, unsigned(4))
274 self
.assertEqual(v3
.shape(), signed(6))
275 v4
= Const(0, unsigned(4)) + Const(0, signed(4))
276 self
.assertEqual(v4
.shape(), signed(6))
277 v5
= 10 + Const(0, 4)
278 self
.assertEqual(v5
.shape(), unsigned(5))
281 v1
= Const(0, unsigned(4)) - Const(0, unsigned(6))
282 self
.assertEqual(repr(v1
), "(- (const 4'd0) (const 6'd0))")
283 self
.assertEqual(v1
.shape(), unsigned(7))
284 v2
= Const(0, signed(4)) - Const(0, signed(6))
285 self
.assertEqual(v2
.shape(), signed(7))
286 v3
= Const(0, signed(4)) - Const(0, unsigned(4))
287 self
.assertEqual(v3
.shape(), signed(6))
288 v4
= Const(0, unsigned(4)) - Const(0, signed(4))
289 self
.assertEqual(v4
.shape(), signed(6))
290 v5
= 10 - Const(0, 4)
291 self
.assertEqual(v5
.shape(), unsigned(5))
294 v1
= Const(0, unsigned(4)) * Const(0, unsigned(6))
295 self
.assertEqual(repr(v1
), "(* (const 4'd0) (const 6'd0))")
296 self
.assertEqual(v1
.shape(), unsigned(10))
297 v2
= Const(0, signed(4)) * Const(0, signed(6))
298 self
.assertEqual(v2
.shape(), signed(10))
299 v3
= Const(0, signed(4)) * Const(0, unsigned(4))
300 self
.assertEqual(v3
.shape(), signed(8))
301 v5
= 10 * Const(0, 4)
302 self
.assertEqual(v5
.shape(), unsigned(8))
305 v1
= Const(0, unsigned(4)) % Const(0, unsigned(6))
306 self
.assertEqual(repr(v1
), "(% (const 4'd0) (const 6'd0))")
307 self
.assertEqual(v1
.shape(), unsigned(4))
308 v3
= Const(0, signed(4)) % Const(0, unsigned(4))
309 self
.assertEqual(v3
.shape(), signed(4))
310 v5
= 10 % Const(0, 4)
311 self
.assertEqual(v5
.shape(), unsigned(4))
313 def test_mod_wrong(self
):
314 with self
.assertRaises(NotImplementedError,
315 msg
="Division by a signed value is not supported"):
316 Const(0, signed(4)) % Const(0, signed(6))
318 def test_floordiv(self
):
319 v1
= Const(0, unsigned(4)) // Const(0, unsigned(6))
320 self
.assertEqual(repr(v1
), "(// (const 4'd0) (const 6'd0))")
321 self
.assertEqual(v1
.shape(), unsigned(4))
322 v3
= Const(0, signed(4)) // Const(0, unsigned(4))
323 self
.assertEqual(v3
.shape(), signed(4))
324 v5
= 10 // Const(0, 4)
325 self
.assertEqual(v5
.shape(), unsigned(4))
327 def test_floordiv_wrong(self
):
328 with self
.assertRaises(NotImplementedError,
329 msg
="Division by a signed value is not supported"):
330 Const(0, signed(4)) // Const(0, signed(6))
333 v1
= Const(0, unsigned(4)) & Const(0, unsigned(6))
334 self
.assertEqual(repr(v1
), "(& (const 4'd0) (const 6'd0))")
335 self
.assertEqual(v1
.shape(), unsigned(6))
336 v2
= Const(0, signed(4)) & Const(0, signed(6))
337 self
.assertEqual(v2
.shape(), signed(6))
338 v3
= Const(0, signed(4)) & Const(0, unsigned(4))
339 self
.assertEqual(v3
.shape(), signed(5))
340 v4
= Const(0, unsigned(4)) & Const(0, signed(4))
341 self
.assertEqual(v4
.shape(), signed(5))
342 v5
= 10 & Const(0, 4)
343 self
.assertEqual(v5
.shape(), unsigned(4))
346 v1
= Const(0, unsigned(4)) |
Const(0, unsigned(6))
347 self
.assertEqual(repr(v1
), "(| (const 4'd0) (const 6'd0))")
348 self
.assertEqual(v1
.shape(), unsigned(6))
349 v2
= Const(0, signed(4)) |
Const(0, signed(6))
350 self
.assertEqual(v2
.shape(), signed(6))
351 v3
= Const(0, signed(4)) |
Const(0, unsigned(4))
352 self
.assertEqual(v3
.shape(), signed(5))
353 v4
= Const(0, unsigned(4)) |
Const(0, signed(4))
354 self
.assertEqual(v4
.shape(), signed(5))
355 v5
= 10 |
Const(0, 4)
356 self
.assertEqual(v5
.shape(), unsigned(4))
359 v1
= Const(0, unsigned(4)) ^
Const(0, unsigned(6))
360 self
.assertEqual(repr(v1
), "(^ (const 4'd0) (const 6'd0))")
361 self
.assertEqual(v1
.shape(), unsigned(6))
362 v2
= Const(0, signed(4)) ^
Const(0, signed(6))
363 self
.assertEqual(v2
.shape(), signed(6))
364 v3
= Const(0, signed(4)) ^
Const(0, unsigned(4))
365 self
.assertEqual(v3
.shape(), signed(5))
366 v4
= Const(0, unsigned(4)) ^
Const(0, signed(4))
367 self
.assertEqual(v4
.shape(), signed(5))
368 v5
= 10 ^
Const(0, 4)
369 self
.assertEqual(v5
.shape(), unsigned(4))
372 v1
= Const(1, 4) << Const(4)
373 self
.assertEqual(repr(v1
), "(<< (const 4'd1) (const 3'd4))")
374 self
.assertEqual(v1
.shape(), unsigned(11))
376 def test_shl_wrong(self
):
377 with self
.assertRaises(NotImplementedError,
378 msg
="Shift by a signed value is not supported"):
379 1 << Const(0, signed(6))
380 with self
.assertRaises(NotImplementedError,
381 msg
="Shift by a signed value is not supported"):
382 Const(1, unsigned(4)) << -1
385 v1
= Const(1, 4) >> Const(4)
386 self
.assertEqual(repr(v1
), "(>> (const 4'd1) (const 3'd4))")
387 self
.assertEqual(v1
.shape(), unsigned(4))
389 def test_shr_wrong(self
):
390 with self
.assertRaises(NotImplementedError,
391 msg
="Shift by a signed value is not supported"):
392 1 << Const(0, signed(6))
393 with self
.assertRaises(NotImplementedError,
394 msg
="Shift by a signed value is not supported"):
395 Const(1, unsigned(4)) << -1
398 v
= Const(0, 4) < Const(0, 6)
399 self
.assertEqual(repr(v
), "(< (const 4'd0) (const 6'd0))")
400 self
.assertEqual(v
.shape(), unsigned(1))
403 v
= Const(0, 4) <= Const(0, 6)
404 self
.assertEqual(repr(v
), "(<= (const 4'd0) (const 6'd0))")
405 self
.assertEqual(v
.shape(), unsigned(1))
408 v
= Const(0, 4) > Const(0, 6)
409 self
.assertEqual(repr(v
), "(> (const 4'd0) (const 6'd0))")
410 self
.assertEqual(v
.shape(), unsigned(1))
413 v
= Const(0, 4) >= Const(0, 6)
414 self
.assertEqual(repr(v
), "(>= (const 4'd0) (const 6'd0))")
415 self
.assertEqual(v
.shape(), unsigned(1))
418 v
= Const(0, 4) == Const(0, 6)
419 self
.assertEqual(repr(v
), "(== (const 4'd0) (const 6'd0))")
420 self
.assertEqual(v
.shape(), unsigned(1))
423 v
= Const(0, 4) != Const(0, 6)
424 self
.assertEqual(repr(v
), "(!= (const 4'd0) (const 6'd0))")
425 self
.assertEqual(v
.shape(), unsigned(1))
429 v1
= Mux(s
, Const(0, unsigned(4)), Const(0, unsigned(6)))
430 self
.assertEqual(repr(v1
), "(m (const 1'd0) (const 4'd0) (const 6'd0))")
431 self
.assertEqual(v1
.shape(), unsigned(6))
432 v2
= Mux(s
, Const(0, signed(4)), Const(0, signed(6)))
433 self
.assertEqual(v2
.shape(), signed(6))
434 v3
= Mux(s
, Const(0, signed(4)), Const(0, unsigned(4)))
435 self
.assertEqual(v3
.shape(), signed(5))
436 v4
= Mux(s
, Const(0, unsigned(4)), Const(0, signed(4)))
437 self
.assertEqual(v4
.shape(), signed(5))
439 def test_mux_wide(self
):
441 v
= Mux(s
, Const(0, unsigned(4)), Const(0, unsigned(6)))
442 self
.assertEqual(repr(v
), "(m (b (const 3'd4)) (const 4'd0) (const 6'd0))")
444 def test_mux_bool(self
):
445 v
= Mux(True, Const(0), Const(0))
446 self
.assertEqual(repr(v
), "(m (const 1'd1) (const 1'd0) (const 1'd0))")
450 self
.assertEqual(repr(v
), "(b (const 1'd0))")
451 self
.assertEqual(v
.shape(), unsigned(1))
454 v
= Const(0b101).any()
455 self
.assertEqual(repr(v
), "(r| (const 3'd5))")
458 v
= Const(0b101).all()
459 self
.assertEqual(repr(v
), "(r& (const 3'd5))")
462 v
= Const(0b101).xor()
463 self
.assertEqual(repr(v
), "(r^ (const 3'd5))")
465 def test_matches(self
):
467 self
.assertRepr(s
.matches(), "(const 1'd0)")
468 self
.assertRepr(s
.matches(1), """
469 (== (sig s) (const 1'd1))
471 self
.assertRepr(s
.matches(0, 1), """
472 (r| (cat (== (sig s) (const 1'd0)) (== (sig s) (const 1'd1))))
474 self
.assertRepr(s
.matches("10--"), """
475 (== (& (sig s) (const 4'd12)) (const 4'd8))
477 self
.assertRepr(s
.matches("1 0--"), """
478 (== (& (sig s) (const 4'd12)) (const 4'd8))
481 def test_matches_enum(self
):
482 s
= Signal(SignedEnum
)
483 self
.assertRepr(s
.matches(SignedEnum
.FOO
), """
484 (== (sig s) (const 1'sd-1))
487 def test_matches_width_wrong(self
):
489 with self
.assertRaises(SyntaxError,
490 msg
="Match pattern '--' must have the same width as match value (which is 4)"):
492 with self
.assertWarns(SyntaxWarning,
493 msg
="Match pattern '10110' is wider than match value (which has width 4); "
494 "comparison will never be true"):
497 def test_matches_bits_wrong(self
):
499 with self
.assertRaises(SyntaxError,
500 msg
="Match pattern 'abc' must consist of 0, 1, and - (don't care) bits, "
501 "and may include whitespace"):
504 def test_matches_pattern_wrong(self
):
506 with self
.assertRaises(SyntaxError,
507 msg
="Match pattern must be an integer, a string, or an enumeration, not 1.0"):
511 with self
.assertRaises(TypeError):
512 hash(Const(0) + Const(0))
515 class SliceTestCase(FHDLTestCase
):
516 def test_shape(self
):
518 self
.assertEqual(s1
.shape(), unsigned(1))
519 self
.assertIsInstance(s1
.shape(), Shape
)
521 self
.assertEqual(s2
.shape(), unsigned(2))
523 def test_start_end_negative(self
):
526 self
.assertEqual((s1
.start
, s1
.stop
), (0, 7))
527 s1
= Slice(c
, -4, -1)
528 self
.assertEqual((s1
.start
, s1
.stop
), (4, 7))
530 def test_start_end_wrong(self
):
531 with self
.assertRaises(TypeError,
532 msg
="Slice start must be an integer, not 'x'"):
534 with self
.assertRaises(TypeError,
535 msg
="Slice stop must be an integer, not 'x'"):
538 def test_start_end_out_of_range(self
):
540 with self
.assertRaises(IndexError,
541 msg
="Cannot start slice 10 bits into 8-bit value"):
543 with self
.assertRaises(IndexError,
544 msg
="Cannot stop slice 12 bits into 8-bit value"):
546 with self
.assertRaises(IndexError,
547 msg
="Slice start 4 must be less than slice stop 2"):
552 self
.assertEqual(repr(s1
), "(slice (const 4'd10) 2:3)")
555 class BitSelectTestCase(FHDLTestCase
):
558 self
.s
= Signal(range(self
.c
.width
))
560 def test_shape(self
):
561 s1
= self
.c
.bit_select(self
.s
, 2)
562 self
.assertIsInstance(s1
, Part
)
563 self
.assertEqual(s1
.shape(), unsigned(2))
564 self
.assertIsInstance(s1
.shape(), Shape
)
565 s2
= self
.c
.bit_select(self
.s
, 0)
566 self
.assertIsInstance(s2
, Part
)
567 self
.assertEqual(s2
.shape(), unsigned(0))
569 def test_stride(self
):
570 s1
= self
.c
.bit_select(self
.s
, 2)
571 self
.assertIsInstance(s1
, Part
)
572 self
.assertEqual(s1
.stride
, 1)
574 def test_const(self
):
575 s1
= self
.c
.bit_select(1, 2)
576 self
.assertIsInstance(s1
, Slice
)
577 self
.assertRepr(s1
, """(slice (const 8'd0) 1:3)""")
579 def test_width_wrong(self
):
580 with self
.assertRaises(TypeError):
581 self
.c
.bit_select(self
.s
, -1)
584 s
= self
.c
.bit_select(self
.s
, 2)
585 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 1)")
588 class WordSelectTestCase(FHDLTestCase
):
591 self
.s
= Signal(range(self
.c
.width
))
593 def test_shape(self
):
594 s1
= self
.c
.word_select(self
.s
, 2)
595 self
.assertIsInstance(s1
, Part
)
596 self
.assertEqual(s1
.shape(), unsigned(2))
597 self
.assertIsInstance(s1
.shape(), Shape
)
599 def test_stride(self
):
600 s1
= self
.c
.word_select(self
.s
, 2)
601 self
.assertIsInstance(s1
, Part
)
602 self
.assertEqual(s1
.stride
, 2)
604 def test_const(self
):
605 s1
= self
.c
.word_select(1, 2)
606 self
.assertIsInstance(s1
, Slice
)
607 self
.assertRepr(s1
, """(slice (const 8'd0) 2:4)""")
609 def test_width_wrong(self
):
610 with self
.assertRaises(TypeError):
611 self
.c
.word_select(self
.s
, 0)
612 with self
.assertRaises(TypeError):
613 self
.c
.word_select(self
.s
, -1)
616 s
= self
.c
.word_select(self
.s
, 2)
617 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 2)")
620 class CatTestCase(FHDLTestCase
):
621 def test_shape(self
):
623 self
.assertEqual(c0
.shape(), unsigned(0))
624 self
.assertIsInstance(c0
.shape(), Shape
)
626 self
.assertEqual(c1
.shape(), unsigned(4))
627 c2
= Cat(Const(10), Const(1))
628 self
.assertEqual(c2
.shape(), unsigned(5))
629 c3
= Cat(Const(10), Const(1), Const(0))
630 self
.assertEqual(c3
.shape(), unsigned(6))
633 c1
= Cat(Const(10), Const(1))
634 self
.assertEqual(repr(c1
), "(cat (const 4'd10) (const 1'd1))")
637 class ReplTestCase(FHDLTestCase
):
638 def test_shape(self
):
639 s1
= Repl(Const(10), 3)
640 self
.assertEqual(s1
.shape(), unsigned(12))
641 self
.assertIsInstance(s1
.shape(), Shape
)
642 s2
= Repl(Const(10), 0)
643 self
.assertEqual(s2
.shape(), unsigned(0))
645 def test_count_wrong(self
):
646 with self
.assertRaises(TypeError):
648 with self
.assertRaises(TypeError):
649 Repl(Const(10), "str")
652 s
= Repl(Const(10), 3)
653 self
.assertEqual(repr(s
), "(repl (const 4'd10) 3)")
656 class ArrayTestCase(FHDLTestCase
):
657 def test_acts_like_array(self
):
659 self
.assertSequenceEqual(a
, [1,2,3])
660 self
.assertEqual(a
[1], 2)
662 self
.assertSequenceEqual(a
, [1,4,3])
664 self
.assertSequenceEqual(a
, [1,3])
666 self
.assertSequenceEqual(a
, [1,2,3])
668 def test_becomes_immutable(self
):
670 s1
= Signal(range(len(a
)))
671 s2
= Signal(range(len(a
)))
674 with self
.assertRaisesRegex(ValueError,
675 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
677 with self
.assertRaisesRegex(ValueError,
678 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
680 with self
.assertRaisesRegex(ValueError,
681 regex
=r
"^Array can no longer be mutated after it was indexed with a value at "):
686 self
.assertEqual(repr(a
), "(array mutable [1, 2, 3])")
687 s
= Signal(range(len(a
)))
689 self
.assertEqual(repr(a
), "(array [1, 2, 3])")
692 class ArrayProxyTestCase(FHDLTestCase
):
693 def test_index_shape(self
):
694 m
= Array(Array(x
* y
for y
in range(1, 4)) for x
in range(1, 4))
698 self
.assertEqual(v
.shape(), unsigned(4))
700 def test_attr_shape(self
):
701 from collections
import namedtuple
702 pair
= namedtuple("pair", ("p", "n"))
703 a
= Array(pair(i
, -i
) for i
in range(10))
704 s
= Signal(range(len(a
)))
706 self
.assertEqual(v
.p
.shape(), unsigned(4))
707 self
.assertEqual(v
.n
.shape(), signed(6))
713 self
.assertEqual(repr(v
), "(proxy (array [1, 2, 3]) (sig s))")
716 class SignalTestCase(FHDLTestCase
):
717 def test_shape(self
):
719 self
.assertEqual(s1
.shape(), unsigned(1))
720 self
.assertIsInstance(s1
.shape(), Shape
)
722 self
.assertEqual(s2
.shape(), unsigned(2))
723 s3
= Signal(unsigned(2))
724 self
.assertEqual(s3
.shape(), unsigned(2))
725 s4
= Signal(signed(2))
726 self
.assertEqual(s4
.shape(), signed(2))
728 self
.assertEqual(s5
.shape(), unsigned(0))
729 s6
= Signal(range(16))
730 self
.assertEqual(s6
.shape(), unsigned(4))
731 s7
= Signal(range(4, 16))
732 self
.assertEqual(s7
.shape(), unsigned(4))
733 s8
= Signal(range(-4, 16))
734 self
.assertEqual(s8
.shape(), signed(5))
735 s9
= Signal(range(-20, 16))
736 self
.assertEqual(s9
.shape(), signed(6))
737 s10
= Signal(range(0))
738 self
.assertEqual(s10
.shape(), unsigned(0))
739 s11
= Signal(range(1))
740 self
.assertEqual(s11
.shape(), unsigned(1))
742 def test_shape_wrong(self
):
743 with self
.assertRaises(TypeError,
744 msg
="Width must be a non-negative integer, not -10"):
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_enum(self
):
759 s1
= Signal(2, reset
=UnsignedEnum
.BAR
)
760 self
.assertEqual(s1
.reset
, 2)
761 with self
.assertRaises(TypeError,
762 msg
="Reset value has to be an int or an integral Enum"
764 Signal(1, reset
=StringEnum
.FOO
)
766 def test_reset_narrow(self
):
767 with self
.assertWarns(SyntaxWarning,
768 msg
="Reset value 8 requires 4 bits to represent, but the signal only has 3 bits"):
770 with self
.assertWarns(SyntaxWarning,
771 msg
="Reset value 4 requires 4 bits to represent, but the signal only has 3 bits"):
772 Signal(signed(3), reset
=4)
773 with self
.assertWarns(SyntaxWarning,
774 msg
="Reset value -5 requires 4 bits to represent, but the signal only has 3 bits"):
775 Signal(signed(3), reset
=-5)
777 def test_attrs(self
):
779 self
.assertEqual(s1
.attrs
, {})
780 s2
= Signal(attrs
={"no_retiming": True})
781 self
.assertEqual(s2
.attrs
, {"no_retiming": True})
785 self
.assertEqual(repr(s1
), "(sig s1)")
788 s1
= Signal
.like(Signal(4))
789 self
.assertEqual(s1
.shape(), unsigned(4))
790 s2
= Signal
.like(Signal(range(-15, 1)))
791 self
.assertEqual(s2
.shape(), signed(5))
792 s3
= Signal
.like(Signal(4, reset
=0b111, reset_less
=True))
793 self
.assertEqual(s3
.reset
, 0b111)
794 self
.assertEqual(s3
.reset_less
, True)
795 s4
= Signal
.like(Signal(attrs
={"no_retiming": True}))
796 self
.assertEqual(s4
.attrs
, {"no_retiming": True})
797 s5
= Signal
.like(Signal(decoder
=str))
798 self
.assertEqual(s5
.decoder
, str)
800 self
.assertEqual(s6
.shape(), unsigned(4))
801 s7
= [Signal
.like(Signal(4))][0]
802 self
.assertEqual(s7
.name
, "$like")
803 s8
= Signal
.like(s1
, name_suffix
="_ff")
804 self
.assertEqual(s8
.name
, "s1_ff")
806 def test_decoder(self
):
810 s
= Signal(decoder
=Color
)
811 self
.assertEqual(s
.decoder(1), "RED/1")
812 self
.assertEqual(s
.decoder(3), "3")
815 s1
= Signal(UnsignedEnum
)
816 self
.assertEqual(s1
.shape(), unsigned(2))
817 s2
= Signal(SignedEnum
)
818 self
.assertEqual(s2
.shape(), signed(2))
819 self
.assertEqual(s2
.decoder(SignedEnum
.FOO
), "FOO/-1")
822 class ClockSignalTestCase(FHDLTestCase
):
823 def test_domain(self
):
825 self
.assertEqual(s1
.domain
, "sync")
826 s2
= ClockSignal("pix")
827 self
.assertEqual(s2
.domain
, "pix")
829 with self
.assertRaises(TypeError,
830 msg
="Clock domain name must be a string, not 1"):
833 def test_shape(self
):
835 self
.assertEqual(s1
.shape(), unsigned(1))
836 self
.assertIsInstance(s1
.shape(), Shape
)
840 self
.assertEqual(repr(s1
), "(clk sync)")
842 def test_wrong_name_comb(self
):
843 with self
.assertRaises(ValueError,
844 msg
="Domain 'comb' does not have a clock"):
848 class ResetSignalTestCase(FHDLTestCase
):
849 def test_domain(self
):
851 self
.assertEqual(s1
.domain
, "sync")
852 s2
= ResetSignal("pix")
853 self
.assertEqual(s2
.domain
, "pix")
855 with self
.assertRaises(TypeError,
856 msg
="Clock domain name must be a string, not 1"):
859 def test_shape(self
):
861 self
.assertEqual(s1
.shape(), unsigned(1))
862 self
.assertIsInstance(s1
.shape(), Shape
)
866 self
.assertEqual(repr(s1
), "(rst sync)")
868 def test_wrong_name_comb(self
):
869 with self
.assertRaises(ValueError,
870 msg
="Domain 'comb' does not have a reset"):
874 class MockUserValue(UserValue
):
875 def __init__(self
, lowered
):
878 self
.lowered
= lowered
881 self
.lower_count
+= 1
885 class UserValueTestCase(FHDLTestCase
):
886 def test_shape(self
):
887 uv
= MockUserValue(1)
888 self
.assertEqual(uv
.shape(), unsigned(1))
889 self
.assertIsInstance(uv
.shape(), Shape
)
891 self
.assertEqual(uv
.shape(), unsigned(1))
892 self
.assertEqual(uv
.lower_count
, 1)
895 class SampleTestCase(FHDLTestCase
):
896 def test_const(self
):
897 s
= Sample(1, 1, "sync")
898 self
.assertEqual(s
.shape(), unsigned(1))
900 def test_signal(self
):
901 s1
= Sample(Signal(2), 1, "sync")
902 self
.assertEqual(s1
.shape(), unsigned(2))
903 s2
= Sample(ClockSignal(), 1, "sync")
904 s3
= Sample(ResetSignal(), 1, "sync")
906 def test_wrong_value_operator(self
):
907 with self
.assertRaises(TypeError,
908 "Sampled value must be a signal or a constant, not "
909 "(+ (sig $signal) (const 1'd1))"):
910 Sample(Signal() + 1, 1, "sync")
912 def test_wrong_clocks_neg(self
):
913 with self
.assertRaises(ValueError,
914 "Cannot sample a value 1 cycles in the future"):
915 Sample(Signal(), -1, "sync")
917 def test_wrong_domain(self
):
918 with self
.assertRaises(TypeError,
919 "Domain name must be a string or None, not 0"):
920 Sample(Signal(), 1, 0)
923 class InitialTestCase(FHDLTestCase
):
924 def test_initial(self
):
926 self
.assertEqual(i
.shape(), unsigned(1))