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
.assertRaisesRegex(TypeError,
39 r
"^Width must be a non-negative integer, not -1$"):
42 def test_compare_wrong(self
):
43 with self
.assertRaisesRegex(TypeError,
44 r
"^Shapes may be compared with other Shapes and \(int, bool\) tuples, not 'hi'$"):
45 Shape(1, True) == 'hi'
47 def test_compare_tuple_wrong(self
):
48 with self
.assertRaisesRegex(TypeError,
49 r
"^Shapes may be compared with other Shapes and \(int, bool\) tuples, not \(2, 3\)$"):
50 Shape(1, True) == (2, 3)
53 self
.assertEqual(repr(Shape()), "unsigned(1)")
54 self
.assertEqual(repr(Shape(2, True)), "signed(2)")
57 width
, signed
= Shape()
58 self
.assertEqual(width
, 1)
59 self
.assertEqual(signed
, False)
61 def test_unsigned(self
):
63 self
.assertIsInstance(s1
, Shape
)
64 self
.assertEqual(s1
.width
, 2)
65 self
.assertEqual(s1
.signed
, False)
67 def test_signed(self
):
69 self
.assertIsInstance(s1
, Shape
)
70 self
.assertEqual(s1
.width
, 2)
71 self
.assertEqual(s1
.signed
, True)
73 def test_cast_shape(self
):
74 s1
= Shape
.cast(unsigned(1))
75 self
.assertEqual(s1
.width
, 1)
76 self
.assertEqual(s1
.signed
, False)
77 s2
= Shape
.cast(signed(3))
78 self
.assertEqual(s2
.width
, 3)
79 self
.assertEqual(s2
.signed
, True)
81 def test_cast_int(self
):
83 self
.assertEqual(s1
.width
, 2)
84 self
.assertEqual(s1
.signed
, False)
86 def test_cast_int_wrong(self
):
87 with self
.assertRaisesRegex(TypeError,
88 r
"^Width must be a non-negative integer, not -1$"):
91 def test_cast_tuple(self
):
92 with warnings
.catch_warnings():
93 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
94 s1
= Shape
.cast((1, True))
95 self
.assertEqual(s1
.width
, 1)
96 self
.assertEqual(s1
.signed
, True)
98 def test_cast_tuple_wrong(self
):
99 with warnings
.catch_warnings():
100 warnings
.filterwarnings(action
="ignore", category
=DeprecationWarning)
101 with self
.assertRaisesRegex(TypeError,
102 r
"^Width must be a non-negative integer, not -1$"):
103 Shape
.cast((-1, True))
105 def test_cast_range(self
):
106 s1
= Shape
.cast(range(0, 8))
107 self
.assertEqual(s1
.width
, 3)
108 self
.assertEqual(s1
.signed
, False)
109 s2
= Shape
.cast(range(0, 9))
110 self
.assertEqual(s2
.width
, 4)
111 self
.assertEqual(s2
.signed
, False)
112 s3
= Shape
.cast(range(-7, 8))
113 self
.assertEqual(s3
.width
, 4)
114 self
.assertEqual(s3
.signed
, True)
115 s4
= Shape
.cast(range(0, 1))
116 self
.assertEqual(s4
.width
, 1)
117 self
.assertEqual(s4
.signed
, False)
118 s5
= Shape
.cast(range(-1, 0))
119 self
.assertEqual(s5
.width
, 1)
120 self
.assertEqual(s5
.signed
, True)
121 s6
= Shape
.cast(range(0, 0))
122 self
.assertEqual(s6
.width
, 0)
123 self
.assertEqual(s6
.signed
, False)
124 s7
= Shape
.cast(range(-1, -1))
125 self
.assertEqual(s7
.width
, 0)
126 self
.assertEqual(s7
.signed
, True)
128 def test_cast_enum(self
):
129 s1
= Shape
.cast(UnsignedEnum
)
130 self
.assertEqual(s1
.width
, 2)
131 self
.assertEqual(s1
.signed
, False)
132 s2
= Shape
.cast(SignedEnum
)
133 self
.assertEqual(s2
.width
, 2)
134 self
.assertEqual(s2
.signed
, True)
136 def test_cast_enum_bad(self
):
137 with self
.assertRaisesRegex(TypeError,
138 r
"^Only enumerations with integer values can be used as value shapes$"):
139 Shape
.cast(StringEnum
)
141 def test_cast_bad(self
):
142 with self
.assertRaisesRegex(TypeError,
143 r
"^Object 'foo' cannot be used as value shape$"):
147 class ValueTestCase(FHDLTestCase
):
149 self
.assertIsInstance(Value
.cast(0), Const
)
150 self
.assertIsInstance(Value
.cast(True), Const
)
152 self
.assertIs(Value
.cast(c
), c
)
153 with self
.assertRaisesRegex(TypeError,
154 r
"^Object 'str' cannot be converted to an nMigen value$"):
157 def test_cast_enum(self
):
158 e1
= Value
.cast(UnsignedEnum
.FOO
)
159 self
.assertIsInstance(e1
, Const
)
160 self
.assertEqual(e1
.shape(), unsigned(2))
161 e2
= Value
.cast(SignedEnum
.FOO
)
162 self
.assertIsInstance(e2
, Const
)
163 self
.assertEqual(e2
.shape(), signed(2))
165 def test_cast_enum_wrong(self
):
166 with self
.assertRaisesRegex(TypeError,
167 r
"^Only enumerations with integer values can be used as value shapes$"):
168 Value
.cast(StringEnum
.FOO
)
171 with self
.assertRaisesRegex(TypeError,
172 r
"^Attempted to convert nMigen value to Python boolean$"):
177 self
.assertEqual(len(Const(10)), 4)
179 def test_getitem_int(self
):
181 self
.assertIsInstance(s1
, Slice
)
182 self
.assertEqual(s1
.start
, 0)
183 self
.assertEqual(s1
.stop
, 1)
185 self
.assertIsInstance(s2
, Slice
)
186 self
.assertEqual(s2
.start
, 3)
187 self
.assertEqual(s2
.stop
, 4)
188 with self
.assertRaisesRegex(IndexError,
189 r
"^Cannot index 5 bits into 4-bit value$"):
192 def test_getitem_slice(self
):
194 self
.assertIsInstance(s1
, Slice
)
195 self
.assertEqual(s1
.start
, 1)
196 self
.assertEqual(s1
.stop
, 3)
198 self
.assertIsInstance(s2
, Slice
)
199 self
.assertEqual(s2
.start
, 1)
200 self
.assertEqual(s2
.stop
, 2)
202 self
.assertIsInstance(s3
, Cat
)
203 self
.assertIsInstance(s3
.parts
[0], Slice
)
204 self
.assertEqual(s3
.parts
[0].start
, 0)
205 self
.assertEqual(s3
.parts
[0].stop
, 1)
206 self
.assertIsInstance(s3
.parts
[1], Slice
)
207 self
.assertEqual(s3
.parts
[1].start
, 2)
208 self
.assertEqual(s3
.parts
[1].stop
, 3)
209 self
.assertIsInstance(s3
.parts
[2], Slice
)
210 self
.assertEqual(s3
.parts
[2].start
, 4)
211 self
.assertEqual(s3
.parts
[2].stop
, 5)
213 def test_getitem_wrong(self
):
214 with self
.assertRaisesRegex(TypeError,
215 r
"^Cannot index value with 'str'$"):
218 def test_shift_left(self
):
219 self
.assertRepr(Const(256, unsigned(9)).shift_left(0),
220 "(cat (const 0'd0) (const 9'd256))")
222 self
.assertRepr(Const(256, unsigned(9)).shift_left(1),
223 "(cat (const 1'd0) (const 9'd256))")
224 self
.assertRepr(Const(256, unsigned(9)).shift_left(5),
225 "(cat (const 5'd0) (const 9'd256))")
226 self
.assertRepr(Const(256, signed(9)).shift_left(1),
227 "(s (cat (const 1'd0) (const 9'sd-256)))")
228 self
.assertRepr(Const(256, signed(9)).shift_left(5),
229 "(s (cat (const 5'd0) (const 9'sd-256)))")
231 self
.assertRepr(Const(256, unsigned(9)).shift_left(-1),
232 "(slice (const 9'd256) 1:9)")
233 self
.assertRepr(Const(256, unsigned(9)).shift_left(-5),
234 "(slice (const 9'd256) 5:9)")
235 self
.assertRepr(Const(256, signed(9)).shift_left(-1),
236 "(s (slice (const 9'sd-256) 1:9))")
237 self
.assertRepr(Const(256, signed(9)).shift_left(-5),
238 "(s (slice (const 9'sd-256) 5:9))")
239 self
.assertRepr(Const(256, signed(9)).shift_left(-15),
240 "(s (slice (const 9'sd-256) 9:9))")
242 def test_shift_left_wrong(self
):
243 with self
.assertRaisesRegex(TypeError,
244 r
"^Shift amount must be an integer, not 'str'$"):
245 Const(31).shift_left("str")
247 def test_shift_right(self
):
248 self
.assertRepr(Const(256, unsigned(9)).shift_right(0),
249 "(slice (const 9'd256) 0:9)")
251 self
.assertRepr(Const(256, unsigned(9)).shift_right(-1),
252 "(cat (const 1'd0) (const 9'd256))")
253 self
.assertRepr(Const(256, unsigned(9)).shift_right(-5),
254 "(cat (const 5'd0) (const 9'd256))")
255 self
.assertRepr(Const(256, signed(9)).shift_right(-1),
256 "(s (cat (const 1'd0) (const 9'sd-256)))")
257 self
.assertRepr(Const(256, signed(9)).shift_right(-5),
258 "(s (cat (const 5'd0) (const 9'sd-256)))")
260 self
.assertRepr(Const(256, unsigned(9)).shift_right(1),
261 "(slice (const 9'd256) 1:9)")
262 self
.assertRepr(Const(256, unsigned(9)).shift_right(5),
263 "(slice (const 9'd256) 5:9)")
264 self
.assertRepr(Const(256, signed(9)).shift_right(1),
265 "(s (slice (const 9'sd-256) 1:9))")
266 self
.assertRepr(Const(256, signed(9)).shift_right(5),
267 "(s (slice (const 9'sd-256) 5:9))")
268 self
.assertRepr(Const(256, signed(9)).shift_right(15),
269 "(s (slice (const 9'sd-256) 9:9))")
271 def test_shift_right_wrong(self
):
272 with self
.assertRaisesRegex(TypeError,
273 r
"^Shift amount must be an integer, not 'str'$"):
274 Const(31).shift_left("str")
276 def test_rotate_left(self
):
277 self
.assertRepr(Const(256).rotate_left(1),
278 "(cat (slice (const 9'd256) 8:9) (slice (const 9'd256) 0:8))")
279 self
.assertRepr(Const(256).rotate_left(7),
280 "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
281 self
.assertRepr(Const(256).rotate_left(-1),
282 "(cat (slice (const 9'd256) 1:9) (slice (const 9'd256) 0:1))")
283 self
.assertRepr(Const(256).rotate_left(-7),
284 "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
286 def test_rotate_left_wrong(self
):
287 with self
.assertRaisesRegex(TypeError,
288 r
"^Rotate amount must be an integer, not 'str'$"):
289 Const(31).rotate_left("str")
291 def test_rotate_right(self
):
292 self
.assertRepr(Const(256).rotate_right(1),
293 "(cat (slice (const 9'd256) 1:9) (slice (const 9'd256) 0:1))")
294 self
.assertRepr(Const(256).rotate_right(7),
295 "(cat (slice (const 9'd256) 7:9) (slice (const 9'd256) 0:7))")
296 self
.assertRepr(Const(256).rotate_right(-1),
297 "(cat (slice (const 9'd256) 8:9) (slice (const 9'd256) 0:8))")
298 self
.assertRepr(Const(256).rotate_right(-7),
299 "(cat (slice (const 9'd256) 2:9) (slice (const 9'd256) 0:2))")
301 def test_rotate_right_wrong(self
):
302 with self
.assertRaisesRegex(TypeError,
303 r
"^Rotate amount must be an integer, not 'str'$"):
304 Const(31).rotate_right("str")
307 class ConstTestCase(FHDLTestCase
):
308 def test_shape(self
):
309 self
.assertEqual(Const(0).shape(), unsigned(1))
310 self
.assertIsInstance(Const(0).shape(), Shape
)
311 self
.assertEqual(Const(1).shape(), unsigned(1))
312 self
.assertEqual(Const(10).shape(), unsigned(4))
313 self
.assertEqual(Const(-10).shape(), signed(5))
315 self
.assertEqual(Const(1, 4).shape(), unsigned(4))
316 self
.assertEqual(Const(-1, 4).shape(), signed(4))
317 self
.assertEqual(Const(1, signed(4)).shape(), signed(4))
318 self
.assertEqual(Const(0, unsigned(0)).shape(), unsigned(0))
320 def test_shape_wrong(self
):
321 with self
.assertRaisesRegex(TypeError,
322 r
"^Width must be a non-negative integer, not -1$"):
325 def test_normalization(self
):
326 self
.assertEqual(Const(0b10110, signed(5)).value
, -10)
328 def test_value(self
):
329 self
.assertEqual(Const(10).value
, 10)
332 self
.assertEqual(repr(Const(10)), "(const 4'd10)")
333 self
.assertEqual(repr(Const(-10)), "(const 5'sd-10)")
336 with self
.assertRaises(TypeError):
340 class OperatorTestCase(FHDLTestCase
):
342 v
= Const(0, 4).bool()
343 self
.assertEqual(repr(v
), "(b (const 4'd0))")
344 self
.assertEqual(v
.shape(), unsigned(1))
346 def test_invert(self
):
348 self
.assertEqual(repr(v
), "(~ (const 4'd0))")
349 self
.assertEqual(v
.shape(), unsigned(4))
351 def test_as_unsigned(self
):
352 v
= Const(-1, signed(4)).as_unsigned()
353 self
.assertEqual(repr(v
), "(u (const 4'sd-1))")
354 self
.assertEqual(v
.shape(), unsigned(4))
356 def test_as_signed(self
):
357 v
= Const(1, unsigned(4)).as_signed()
358 self
.assertEqual(repr(v
), "(s (const 4'd1))")
359 self
.assertEqual(v
.shape(), signed(4))
362 v1
= -Const(0, unsigned(4))
363 self
.assertEqual(repr(v1
), "(- (const 4'd0))")
364 self
.assertEqual(v1
.shape(), signed(5))
365 v2
= -Const(0, signed(4))
366 self
.assertEqual(repr(v2
), "(- (const 4'sd0))")
367 self
.assertEqual(v2
.shape(), signed(5))
370 v1
= Const(0, unsigned(4)) + Const(0, unsigned(6))
371 self
.assertEqual(repr(v1
), "(+ (const 4'd0) (const 6'd0))")
372 self
.assertEqual(v1
.shape(), unsigned(7))
373 v2
= Const(0, signed(4)) + Const(0, signed(6))
374 self
.assertEqual(v2
.shape(), signed(7))
375 v3
= Const(0, signed(4)) + Const(0, unsigned(4))
376 self
.assertEqual(v3
.shape(), signed(6))
377 v4
= Const(0, unsigned(4)) + Const(0, signed(4))
378 self
.assertEqual(v4
.shape(), signed(6))
379 v5
= 10 + Const(0, 4)
380 self
.assertEqual(v5
.shape(), unsigned(5))
383 v1
= Const(0, unsigned(4)) - Const(0, unsigned(6))
384 self
.assertEqual(repr(v1
), "(- (const 4'd0) (const 6'd0))")
385 self
.assertEqual(v1
.shape(), unsigned(7))
386 v2
= Const(0, signed(4)) - Const(0, signed(6))
387 self
.assertEqual(v2
.shape(), signed(7))
388 v3
= Const(0, signed(4)) - Const(0, unsigned(4))
389 self
.assertEqual(v3
.shape(), signed(6))
390 v4
= Const(0, unsigned(4)) - Const(0, signed(4))
391 self
.assertEqual(v4
.shape(), signed(6))
392 v5
= 10 - Const(0, 4)
393 self
.assertEqual(v5
.shape(), unsigned(5))
396 v1
= Const(0, unsigned(4)) * Const(0, unsigned(6))
397 self
.assertEqual(repr(v1
), "(* (const 4'd0) (const 6'd0))")
398 self
.assertEqual(v1
.shape(), unsigned(10))
399 v2
= Const(0, signed(4)) * Const(0, signed(6))
400 self
.assertEqual(v2
.shape(), signed(10))
401 v3
= Const(0, signed(4)) * Const(0, unsigned(4))
402 self
.assertEqual(v3
.shape(), signed(8))
403 v5
= 10 * Const(0, 4)
404 self
.assertEqual(v5
.shape(), unsigned(8))
407 v1
= Const(0, unsigned(4)) % Const(0, unsigned(6))
408 self
.assertEqual(repr(v1
), "(% (const 4'd0) (const 6'd0))")
409 self
.assertEqual(v1
.shape(), unsigned(4))
410 v3
= Const(0, signed(4)) % Const(0, unsigned(4))
411 self
.assertEqual(v3
.shape(), signed(4))
412 v5
= 10 % Const(0, 4)
413 self
.assertEqual(v5
.shape(), unsigned(4))
415 def test_mod_wrong(self
):
416 with self
.assertRaisesRegex(NotImplementedError,
417 r
"^Division by a signed value is not supported$"):
418 Const(0, signed(4)) % Const(0, signed(6))
420 def test_floordiv(self
):
421 v1
= Const(0, unsigned(4)) // Const(0, unsigned(6))
422 self
.assertEqual(repr(v1
), "(// (const 4'd0) (const 6'd0))")
423 self
.assertEqual(v1
.shape(), unsigned(4))
424 v3
= Const(0, signed(4)) // Const(0, unsigned(4))
425 self
.assertEqual(v3
.shape(), signed(4))
426 v5
= 10 // Const(0, 4)
427 self
.assertEqual(v5
.shape(), unsigned(4))
429 def test_floordiv_wrong(self
):
430 with self
.assertRaisesRegex(NotImplementedError,
431 r
"^Division by a signed value is not supported$"):
432 Const(0, signed(4)) // Const(0, signed(6))
435 v1
= Const(0, unsigned(4)) & Const(0, unsigned(6))
436 self
.assertEqual(repr(v1
), "(& (const 4'd0) (const 6'd0))")
437 self
.assertEqual(v1
.shape(), unsigned(6))
438 v2
= Const(0, signed(4)) & Const(0, signed(6))
439 self
.assertEqual(v2
.shape(), signed(6))
440 v3
= Const(0, signed(4)) & Const(0, unsigned(4))
441 self
.assertEqual(v3
.shape(), signed(5))
442 v4
= Const(0, unsigned(4)) & Const(0, signed(4))
443 self
.assertEqual(v4
.shape(), signed(5))
444 v5
= 10 & Const(0, 4)
445 self
.assertEqual(v5
.shape(), unsigned(4))
448 v1
= Const(0, unsigned(4)) |
Const(0, unsigned(6))
449 self
.assertEqual(repr(v1
), "(| (const 4'd0) (const 6'd0))")
450 self
.assertEqual(v1
.shape(), unsigned(6))
451 v2
= Const(0, signed(4)) |
Const(0, signed(6))
452 self
.assertEqual(v2
.shape(), signed(6))
453 v3
= Const(0, signed(4)) |
Const(0, unsigned(4))
454 self
.assertEqual(v3
.shape(), signed(5))
455 v4
= Const(0, unsigned(4)) |
Const(0, signed(4))
456 self
.assertEqual(v4
.shape(), signed(5))
457 v5
= 10 |
Const(0, 4)
458 self
.assertEqual(v5
.shape(), unsigned(4))
461 v1
= Const(0, unsigned(4)) ^
Const(0, unsigned(6))
462 self
.assertEqual(repr(v1
), "(^ (const 4'd0) (const 6'd0))")
463 self
.assertEqual(v1
.shape(), unsigned(6))
464 v2
= Const(0, signed(4)) ^
Const(0, signed(6))
465 self
.assertEqual(v2
.shape(), signed(6))
466 v3
= Const(0, signed(4)) ^
Const(0, unsigned(4))
467 self
.assertEqual(v3
.shape(), signed(5))
468 v4
= Const(0, unsigned(4)) ^
Const(0, signed(4))
469 self
.assertEqual(v4
.shape(), signed(5))
470 v5
= 10 ^
Const(0, 4)
471 self
.assertEqual(v5
.shape(), unsigned(4))
474 v1
= Const(1, 4) << Const(4)
475 self
.assertEqual(repr(v1
), "(<< (const 4'd1) (const 3'd4))")
476 self
.assertEqual(v1
.shape(), unsigned(11))
478 def test_shl_wrong(self
):
479 with self
.assertRaisesRegex(TypeError,
480 r
"^Shift amount must be unsigned$"):
481 1 << Const(0, signed(6))
482 with self
.assertRaisesRegex(TypeError,
483 r
"^Shift amount must be unsigned$"):
484 Const(1, unsigned(4)) << -1
487 v1
= Const(1, 4) >> Const(4)
488 self
.assertEqual(repr(v1
), "(>> (const 4'd1) (const 3'd4))")
489 self
.assertEqual(v1
.shape(), unsigned(4))
491 def test_shr_wrong(self
):
492 with self
.assertRaisesRegex(TypeError,
493 r
"^Shift amount must be unsigned$"):
494 1 << Const(0, signed(6))
495 with self
.assertRaisesRegex(TypeError,
496 r
"^Shift amount must be unsigned$"):
497 Const(1, unsigned(4)) << -1
500 v
= Const(0, 4) < Const(0, 6)
501 self
.assertEqual(repr(v
), "(< (const 4'd0) (const 6'd0))")
502 self
.assertEqual(v
.shape(), unsigned(1))
505 v
= Const(0, 4) <= Const(0, 6)
506 self
.assertEqual(repr(v
), "(<= (const 4'd0) (const 6'd0))")
507 self
.assertEqual(v
.shape(), unsigned(1))
510 v
= Const(0, 4) > Const(0, 6)
511 self
.assertEqual(repr(v
), "(> (const 4'd0) (const 6'd0))")
512 self
.assertEqual(v
.shape(), unsigned(1))
515 v
= Const(0, 4) >= Const(0, 6)
516 self
.assertEqual(repr(v
), "(>= (const 4'd0) (const 6'd0))")
517 self
.assertEqual(v
.shape(), unsigned(1))
520 v
= Const(0, 4) == Const(0, 6)
521 self
.assertEqual(repr(v
), "(== (const 4'd0) (const 6'd0))")
522 self
.assertEqual(v
.shape(), unsigned(1))
525 v
= Const(0, 4) != Const(0, 6)
526 self
.assertEqual(repr(v
), "(!= (const 4'd0) (const 6'd0))")
527 self
.assertEqual(v
.shape(), unsigned(1))
531 v1
= Mux(s
, Const(0, unsigned(4)), Const(0, unsigned(6)))
532 self
.assertEqual(repr(v1
), "(m (const 1'd0) (const 4'd0) (const 6'd0))")
533 self
.assertEqual(v1
.shape(), unsigned(6))
534 v2
= Mux(s
, Const(0, signed(4)), Const(0, signed(6)))
535 self
.assertEqual(v2
.shape(), signed(6))
536 v3
= Mux(s
, Const(0, signed(4)), Const(0, unsigned(4)))
537 self
.assertEqual(v3
.shape(), signed(5))
538 v4
= Mux(s
, Const(0, unsigned(4)), Const(0, signed(4)))
539 self
.assertEqual(v4
.shape(), signed(5))
541 def test_mux_wide(self
):
543 v
= Mux(s
, Const(0, unsigned(4)), Const(0, unsigned(6)))
544 self
.assertEqual(repr(v
), "(m (b (const 3'd4)) (const 4'd0) (const 6'd0))")
546 def test_mux_bool(self
):
547 v
= Mux(True, Const(0), Const(0))
548 self
.assertEqual(repr(v
), "(m (const 1'd1) (const 1'd0) (const 1'd0))")
552 self
.assertEqual(repr(v
), "(b (const 1'd0))")
553 self
.assertEqual(v
.shape(), unsigned(1))
556 v
= Const(0b101).any()
557 self
.assertEqual(repr(v
), "(r| (const 3'd5))")
560 v
= Const(0b101).all()
561 self
.assertEqual(repr(v
), "(r& (const 3'd5))")
564 v
= Const(0b101).xor()
565 self
.assertEqual(repr(v
), "(r^ (const 3'd5))")
567 def test_matches(self
):
569 self
.assertRepr(s
.matches(), "(const 1'd0)")
570 self
.assertRepr(s
.matches(1), """
571 (== (sig s) (const 1'd1))
573 self
.assertRepr(s
.matches(0, 1), """
574 (r| (cat (== (sig s) (const 1'd0)) (== (sig s) (const 1'd1))))
576 self
.assertRepr(s
.matches("10--"), """
577 (== (& (sig s) (const 4'd12)) (const 4'd8))
579 self
.assertRepr(s
.matches("1 0--"), """
580 (== (& (sig s) (const 4'd12)) (const 4'd8))
583 def test_matches_enum(self
):
584 s
= Signal(SignedEnum
)
585 self
.assertRepr(s
.matches(SignedEnum
.FOO
), """
586 (== (sig s) (const 1'sd-1))
589 def test_matches_width_wrong(self
):
591 with self
.assertRaisesRegex(SyntaxError,
592 r
"^Match pattern '--' must have the same width as match value \(which is 4\)$"):
594 with self
.assertWarnsRegex(SyntaxWarning,
595 (r
"^Match pattern '10110' is wider than match value \(which has width 4\); "
596 r
"comparison will never be true$")):
599 def test_matches_bits_wrong(self
):
601 with self
.assertRaisesRegex(SyntaxError,
602 (r
"^Match pattern 'abc' must consist of 0, 1, and - \(don't care\) bits, "
603 r
"and may include whitespace$")):
606 def test_matches_pattern_wrong(self
):
608 with self
.assertRaisesRegex(SyntaxError,
609 r
"^Match pattern must be an integer, a string, or an enumeration, not 1\.0$"):
613 with self
.assertRaises(TypeError):
614 hash(Const(0) + Const(0))
617 class SliceTestCase(FHDLTestCase
):
618 def test_shape(self
):
620 self
.assertEqual(s1
.shape(), unsigned(1))
621 self
.assertIsInstance(s1
.shape(), Shape
)
623 self
.assertEqual(s2
.shape(), unsigned(2))
625 def test_start_end_negative(self
):
628 self
.assertEqual((s1
.start
, s1
.stop
), (0, 7))
629 s1
= Slice(c
, -4, -1)
630 self
.assertEqual((s1
.start
, s1
.stop
), (4, 7))
632 def test_start_end_wrong(self
):
633 with self
.assertRaisesRegex(TypeError,
634 r
"^Slice start must be an integer, not 'x'$"):
636 with self
.assertRaisesRegex(TypeError,
637 r
"^Slice stop must be an integer, not 'x'$"):
640 def test_start_end_out_of_range(self
):
642 with self
.assertRaisesRegex(IndexError,
643 r
"^Cannot start slice 10 bits into 8-bit value$"):
645 with self
.assertRaisesRegex(IndexError,
646 r
"^Cannot stop slice 12 bits into 8-bit value$"):
648 with self
.assertRaisesRegex(IndexError,
649 r
"^Slice start 4 must be less than slice stop 2$"):
654 self
.assertEqual(repr(s1
), "(slice (const 4'd10) 2:3)")
657 class BitSelectTestCase(FHDLTestCase
):
660 self
.s
= Signal(range(self
.c
.width
))
662 def test_shape(self
):
663 s1
= self
.c
.bit_select(self
.s
, 2)
664 self
.assertIsInstance(s1
, Part
)
665 self
.assertEqual(s1
.shape(), unsigned(2))
666 self
.assertIsInstance(s1
.shape(), Shape
)
667 s2
= self
.c
.bit_select(self
.s
, 0)
668 self
.assertIsInstance(s2
, Part
)
669 self
.assertEqual(s2
.shape(), unsigned(0))
671 def test_stride(self
):
672 s1
= self
.c
.bit_select(self
.s
, 2)
673 self
.assertIsInstance(s1
, Part
)
674 self
.assertEqual(s1
.stride
, 1)
676 def test_const(self
):
677 s1
= self
.c
.bit_select(1, 2)
678 self
.assertIsInstance(s1
, Slice
)
679 self
.assertRepr(s1
, """(slice (const 8'd0) 1:3)""")
681 def test_width_wrong(self
):
682 with self
.assertRaises(TypeError):
683 self
.c
.bit_select(self
.s
, -1)
686 s
= self
.c
.bit_select(self
.s
, 2)
687 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 1)")
690 class WordSelectTestCase(FHDLTestCase
):
693 self
.s
= Signal(range(self
.c
.width
))
695 def test_shape(self
):
696 s1
= self
.c
.word_select(self
.s
, 2)
697 self
.assertIsInstance(s1
, Part
)
698 self
.assertEqual(s1
.shape(), unsigned(2))
699 self
.assertIsInstance(s1
.shape(), Shape
)
701 def test_stride(self
):
702 s1
= self
.c
.word_select(self
.s
, 2)
703 self
.assertIsInstance(s1
, Part
)
704 self
.assertEqual(s1
.stride
, 2)
706 def test_const(self
):
707 s1
= self
.c
.word_select(1, 2)
708 self
.assertIsInstance(s1
, Slice
)
709 self
.assertRepr(s1
, """(slice (const 8'd0) 2:4)""")
711 def test_width_wrong(self
):
712 with self
.assertRaises(TypeError):
713 self
.c
.word_select(self
.s
, 0)
714 with self
.assertRaises(TypeError):
715 self
.c
.word_select(self
.s
, -1)
718 s
= self
.c
.word_select(self
.s
, 2)
719 self
.assertEqual(repr(s
), "(part (const 8'd0) (sig s) 2 2)")
722 class CatTestCase(FHDLTestCase
):
723 def test_shape(self
):
725 self
.assertEqual(c0
.shape(), unsigned(0))
726 self
.assertIsInstance(c0
.shape(), Shape
)
728 self
.assertEqual(c1
.shape(), unsigned(4))
729 c2
= Cat(Const(10), Const(1))
730 self
.assertEqual(c2
.shape(), unsigned(5))
731 c3
= Cat(Const(10), Const(1), Const(0))
732 self
.assertEqual(c3
.shape(), unsigned(6))
735 c1
= Cat(Const(10), Const(1))
736 self
.assertEqual(repr(c1
), "(cat (const 4'd10) (const 1'd1))")
739 class ReplTestCase(FHDLTestCase
):
740 def test_shape(self
):
741 s1
= Repl(Const(10), 3)
742 self
.assertEqual(s1
.shape(), unsigned(12))
743 self
.assertIsInstance(s1
.shape(), Shape
)
744 s2
= Repl(Const(10), 0)
745 self
.assertEqual(s2
.shape(), unsigned(0))
747 def test_count_wrong(self
):
748 with self
.assertRaises(TypeError):
750 with self
.assertRaises(TypeError):
751 Repl(Const(10), "str")
754 s
= Repl(Const(10), 3)
755 self
.assertEqual(repr(s
), "(repl (const 4'd10) 3)")
758 class ArrayTestCase(FHDLTestCase
):
759 def test_acts_like_array(self
):
761 self
.assertSequenceEqual(a
, [1,2,3])
762 self
.assertEqual(a
[1], 2)
764 self
.assertSequenceEqual(a
, [1,4,3])
766 self
.assertSequenceEqual(a
, [1,3])
768 self
.assertSequenceEqual(a
, [1,2,3])
770 def test_becomes_immutable(self
):
772 s1
= Signal(range(len(a
)))
773 s2
= Signal(range(len(a
)))
776 with self
.assertRaisesRegex(ValueError,
777 r
"^Array can no longer be mutated after it was indexed with a value at "):
779 with self
.assertRaisesRegex(ValueError,
780 r
"^Array can no longer be mutated after it was indexed with a value at "):
782 with self
.assertRaisesRegex(ValueError,
783 r
"^Array can no longer be mutated after it was indexed with a value at "):
788 self
.assertEqual(repr(a
), "(array mutable [1, 2, 3])")
789 s
= Signal(range(len(a
)))
791 self
.assertEqual(repr(a
), "(array [1, 2, 3])")
794 class ArrayProxyTestCase(FHDLTestCase
):
795 def test_index_shape(self
):
796 m
= Array(Array(x
* y
for y
in range(1, 4)) for x
in range(1, 4))
800 self
.assertEqual(v
.shape(), unsigned(4))
802 def test_attr_shape(self
):
803 from collections
import namedtuple
804 pair
= namedtuple("pair", ("p", "n"))
805 a
= Array(pair(i
, -i
) for i
in range(10))
806 s
= Signal(range(len(a
)))
808 self
.assertEqual(v
.p
.shape(), unsigned(4))
809 self
.assertEqual(v
.n
.shape(), signed(5))
811 def test_attr_shape_signed(self
):
812 # [unsigned(1), unsigned(1)] → unsigned(1)
815 self
.assertEqual(v1
.shape(), unsigned(1))
816 # [signed(1), signed(1)] → signed(1)
819 self
.assertEqual(v2
.shape(), signed(1))
820 # [unsigned(1), signed(2)] → signed(2)
823 self
.assertEqual(v3
.shape(), signed(2))
824 # [unsigned(1), signed(1)] → signed(2); 1st operand padded with sign bit!
827 self
.assertEqual(v4
.shape(), signed(2))
828 # [unsigned(2), signed(1)] → signed(3); 1st operand padded with sign bit!
831 self
.assertEqual(v5
.shape(), signed(2))
837 self
.assertEqual(repr(v
), "(proxy (array [1, 2, 3]) (sig s))")
840 class SignalTestCase(FHDLTestCase
):
841 def test_shape(self
):
843 self
.assertEqual(s1
.shape(), unsigned(1))
844 self
.assertIsInstance(s1
.shape(), Shape
)
846 self
.assertEqual(s2
.shape(), unsigned(2))
847 s3
= Signal(unsigned(2))
848 self
.assertEqual(s3
.shape(), unsigned(2))
849 s4
= Signal(signed(2))
850 self
.assertEqual(s4
.shape(), signed(2))
852 self
.assertEqual(s5
.shape(), unsigned(0))
853 s6
= Signal(range(16))
854 self
.assertEqual(s6
.shape(), unsigned(4))
855 s7
= Signal(range(4, 16))
856 self
.assertEqual(s7
.shape(), unsigned(4))
857 s8
= Signal(range(-4, 16))
858 self
.assertEqual(s8
.shape(), signed(5))
859 s9
= Signal(range(-20, 16))
860 self
.assertEqual(s9
.shape(), signed(6))
861 s10
= Signal(range(0))
862 self
.assertEqual(s10
.shape(), unsigned(0))
863 s11
= Signal(range(1))
864 self
.assertEqual(s11
.shape(), unsigned(1))
866 def test_shape_wrong(self
):
867 with self
.assertRaisesRegex(TypeError,
868 r
"^Width must be a non-negative integer, not -10$"):
873 self
.assertEqual(s1
.name
, "s1")
874 s2
= Signal(name
="sig")
875 self
.assertEqual(s2
.name
, "sig")
877 def test_reset(self
):
878 s1
= Signal(4, reset
=0b111, reset_less
=True)
879 self
.assertEqual(s1
.reset
, 0b111)
880 self
.assertEqual(s1
.reset_less
, True)
882 def test_reset_enum(self
):
883 s1
= Signal(2, reset
=UnsignedEnum
.BAR
)
884 self
.assertEqual(s1
.reset
, 2)
885 with self
.assertRaisesRegex(TypeError,
886 r
"^Reset value has to be an int or an integral Enum$"
888 Signal(1, reset
=StringEnum
.FOO
)
890 def test_reset_narrow(self
):
891 with self
.assertWarnsRegex(SyntaxWarning,
892 r
"^Reset value 8 requires 4 bits to represent, but the signal only has 3 bits$"):
894 with self
.assertWarnsRegex(SyntaxWarning,
895 r
"^Reset value 4 requires 4 bits to represent, but the signal only has 3 bits$"):
896 Signal(signed(3), reset
=4)
897 with self
.assertWarnsRegex(SyntaxWarning,
898 r
"^Reset value -5 requires 4 bits to represent, but the signal only has 3 bits$"):
899 Signal(signed(3), reset
=-5)
901 def test_attrs(self
):
903 self
.assertEqual(s1
.attrs
, {})
904 s2
= Signal(attrs
={"no_retiming": True})
905 self
.assertEqual(s2
.attrs
, {"no_retiming": True})
909 self
.assertEqual(repr(s1
), "(sig s1)")
912 s1
= Signal
.like(Signal(4))
913 self
.assertEqual(s1
.shape(), unsigned(4))
914 s2
= Signal
.like(Signal(range(-15, 1)))
915 self
.assertEqual(s2
.shape(), signed(5))
916 s3
= Signal
.like(Signal(4, reset
=0b111, reset_less
=True))
917 self
.assertEqual(s3
.reset
, 0b111)
918 self
.assertEqual(s3
.reset_less
, True)
919 s4
= Signal
.like(Signal(attrs
={"no_retiming": True}))
920 self
.assertEqual(s4
.attrs
, {"no_retiming": True})
921 s5
= Signal
.like(Signal(decoder
=str))
922 self
.assertEqual(s5
.decoder
, str)
924 self
.assertEqual(s6
.shape(), unsigned(4))
925 s7
= [Signal
.like(Signal(4))][0]
926 self
.assertEqual(s7
.name
, "$like")
927 s8
= Signal
.like(s1
, name_suffix
="_ff")
928 self
.assertEqual(s8
.name
, "s1_ff")
930 def test_decoder(self
):
934 s
= Signal(decoder
=Color
)
935 self
.assertEqual(s
.decoder(1), "RED/1")
936 self
.assertEqual(s
.decoder(3), "3")
939 s1
= Signal(UnsignedEnum
)
940 self
.assertEqual(s1
.shape(), unsigned(2))
941 s2
= Signal(SignedEnum
)
942 self
.assertEqual(s2
.shape(), signed(2))
943 self
.assertEqual(s2
.decoder(SignedEnum
.FOO
), "FOO/-1")
946 class ClockSignalTestCase(FHDLTestCase
):
947 def test_domain(self
):
949 self
.assertEqual(s1
.domain
, "sync")
950 s2
= ClockSignal("pix")
951 self
.assertEqual(s2
.domain
, "pix")
953 with self
.assertRaisesRegex(TypeError,
954 r
"^Clock domain name must be a string, not 1$"):
957 def test_shape(self
):
959 self
.assertEqual(s1
.shape(), unsigned(1))
960 self
.assertIsInstance(s1
.shape(), Shape
)
964 self
.assertEqual(repr(s1
), "(clk sync)")
966 def test_wrong_name_comb(self
):
967 with self
.assertRaisesRegex(ValueError,
968 r
"^Domain 'comb' does not have a clock$"):
972 class ResetSignalTestCase(FHDLTestCase
):
973 def test_domain(self
):
975 self
.assertEqual(s1
.domain
, "sync")
976 s2
= ResetSignal("pix")
977 self
.assertEqual(s2
.domain
, "pix")
979 with self
.assertRaisesRegex(TypeError,
980 r
"^Clock domain name must be a string, not 1$"):
983 def test_shape(self
):
985 self
.assertEqual(s1
.shape(), unsigned(1))
986 self
.assertIsInstance(s1
.shape(), Shape
)
990 self
.assertEqual(repr(s1
), "(rst sync)")
992 def test_wrong_name_comb(self
):
993 with self
.assertRaisesRegex(ValueError,
994 r
"^Domain 'comb' does not have a reset$"):
998 class MockUserValue(UserValue
):
999 def __init__(self
, lowered
):
1001 self
.lower_count
= 0
1002 self
.lowered
= lowered
1005 self
.lower_count
+= 1
1009 class UserValueTestCase(FHDLTestCase
):
1010 def test_shape(self
):
1011 uv
= MockUserValue(1)
1012 self
.assertEqual(uv
.shape(), unsigned(1))
1013 self
.assertIsInstance(uv
.shape(), Shape
)
1015 self
.assertEqual(uv
.shape(), unsigned(1))
1016 self
.assertEqual(uv
.lower_count
, 1)
1018 def test_lower_to_user_value(self
):
1019 uv
= MockUserValue(MockUserValue(1))
1020 self
.assertEqual(uv
.shape(), unsigned(1))
1021 self
.assertIsInstance(uv
.shape(), Shape
)
1022 uv
.lowered
= MockUserValue(2)
1023 self
.assertEqual(uv
.shape(), unsigned(1))
1024 self
.assertEqual(uv
.lower_count
, 1)
1027 class SampleTestCase(FHDLTestCase
):
1028 def test_const(self
):
1029 s
= Sample(1, 1, "sync")
1030 self
.assertEqual(s
.shape(), unsigned(1))
1032 def test_signal(self
):
1033 s1
= Sample(Signal(2), 1, "sync")
1034 self
.assertEqual(s1
.shape(), unsigned(2))
1035 s2
= Sample(ClockSignal(), 1, "sync")
1036 s3
= Sample(ResetSignal(), 1, "sync")
1038 def test_wrong_value_operator(self
):
1039 with self
.assertRaisesRegex(TypeError,
1040 (r
"^Sampled value must be a signal or a constant, not "
1041 r
"\(\+ \(sig \$signal\) \(const 1'd1\)\)$")):
1042 Sample(Signal() + 1, 1, "sync")
1044 def test_wrong_clocks_neg(self
):
1045 with self
.assertRaisesRegex(ValueError,
1046 r
"^Cannot sample a value 1 cycles in the future$"):
1047 Sample(Signal(), -1, "sync")
1049 def test_wrong_domain(self
):
1050 with self
.assertRaisesRegex(TypeError,
1051 r
"^Domain name must be a string or None, not 0$"):
1052 Sample(Signal(), 1, 0)
1055 class InitialTestCase(FHDLTestCase
):
1056 def test_initial(self
):
1058 self
.assertEqual(i
.shape(), unsigned(1))