hdl.ast: add Value.{as_signed,as_unsigned}.
[nmigen.git] / nmigen / test / test_hdl_ast.py
1 import warnings
2 from enum import Enum
3
4 from ..hdl.ast import *
5 from .utils import *
6
7
8 class UnsignedEnum(Enum):
9 FOO = 1
10 BAR = 2
11 BAZ = 3
12
13
14 class SignedEnum(Enum):
15 FOO = -1
16 BAR = 0
17 BAZ = +1
18
19
20 class StringEnum(Enum):
21 FOO = "a"
22 BAR = "b"
23
24
25 class ShapeTestCase(FHDLTestCase):
26 def test_make(self):
27 s1 = Shape()
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)
33 s3 = Shape(3, True)
34 self.assertEqual(s3.width, 3)
35 self.assertEqual(s3.signed, True)
36
37 def test_make_wrong(self):
38 with self.assertRaises(TypeError,
39 msg="Width must be a non-negative integer, not -1"):
40 Shape(-1)
41
42 def test_tuple(self):
43 width, signed = Shape()
44 self.assertEqual(width, 1)
45 self.assertEqual(signed, False)
46
47 def test_unsigned(self):
48 s1 = unsigned(2)
49 self.assertIsInstance(s1, Shape)
50 self.assertEqual(s1.width, 2)
51 self.assertEqual(s1.signed, False)
52
53 def test_signed(self):
54 s1 = signed(2)
55 self.assertIsInstance(s1, Shape)
56 self.assertEqual(s1.width, 2)
57 self.assertEqual(s1.signed, True)
58
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)
66
67 def test_cast_int(self):
68 s1 = Shape.cast(2)
69 self.assertEqual(s1.width, 2)
70 self.assertEqual(s1.signed, False)
71
72 def test_cast_int_wrong(self):
73 with self.assertRaises(TypeError,
74 msg="Width must be a non-negative integer, not -1"):
75 Shape.cast(-1)
76
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)
83
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))
90
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)
113
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)
121
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)
126
127 def test_cast_bad(self):
128 with self.assertRaises(TypeError,
129 msg="Object 'foo' cannot be used as value shape"):
130 Shape.cast("foo")
131
132
133 class ValueTestCase(FHDLTestCase):
134 def test_cast(self):
135 self.assertIsInstance(Value.cast(0), Const)
136 self.assertIsInstance(Value.cast(True), Const)
137 c = Const(0)
138 self.assertIs(Value.cast(c), c)
139 with self.assertRaises(TypeError,
140 msg="Object 'str' cannot be converted to an nMigen value"):
141 Value.cast("str")
142
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))
150
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)
155
156 def test_bool(self):
157 with self.assertRaises(TypeError,
158 msg="Attempted to convert nMigen value to boolean"):
159 if Const(0):
160 pass
161
162 def test_len(self):
163 self.assertEqual(len(Const(10)), 4)
164
165 def test_getitem_int(self):
166 s1 = Const(10)[0]
167 self.assertIsInstance(s1, Slice)
168 self.assertEqual(s1.start, 0)
169 self.assertEqual(s1.stop, 1)
170 s2 = Const(10)[-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"):
176 Const(10)[5]
177
178 def test_getitem_slice(self):
179 s1 = Const(10)[1:3]
180 self.assertIsInstance(s1, Slice)
181 self.assertEqual(s1.start, 1)
182 self.assertEqual(s1.stop, 3)
183 s2 = Const(10)[1:-2]
184 self.assertIsInstance(s2, Slice)
185 self.assertEqual(s2.start, 1)
186 self.assertEqual(s2.stop, 2)
187 s3 = Const(31)[::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)
198
199 def test_getitem_wrong(self):
200 with self.assertRaises(TypeError,
201 msg="Cannot index value with 'str'"):
202 Const(31)["str"]
203
204
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))
212
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))
217
218 def test_shape_wrong(self):
219 with self.assertRaises(TypeError,
220 msg="Width must be a non-negative integer, not -1"):
221 Const(1, -1)
222
223 def test_normalization(self):
224 self.assertEqual(Const(0b10110, signed(5)).value, -10)
225
226 def test_value(self):
227 self.assertEqual(Const(10).value, 10)
228
229 def test_repr(self):
230 self.assertEqual(repr(Const(10)), "(const 4'd10)")
231 self.assertEqual(repr(Const(-10)), "(const 5'sd-10)")
232
233 def test_hash(self):
234 with self.assertRaises(TypeError):
235 hash(Const(0))
236
237
238 class OperatorTestCase(FHDLTestCase):
239 def test_bool(self):
240 v = Const(0, 4).bool()
241 self.assertEqual(repr(v), "(b (const 4'd0))")
242 self.assertEqual(v.shape(), unsigned(1))
243
244 def test_invert(self):
245 v = ~Const(0, 4)
246 self.assertEqual(repr(v), "(~ (const 4'd0))")
247 self.assertEqual(v.shape(), unsigned(4))
248
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))
253
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))
258
259 def test_neg(self):
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))
266
267 def test_add(self):
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))
279
280 def test_sub(self):
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))
292
293 def test_mul(self):
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))
303
304 def test_mod(self):
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))
312
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))
317
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))
326
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))
331
332 def test_and(self):
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))
344
345 def test_or(self):
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))
357
358 def test_xor(self):
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))
370
371 def test_shl(self):
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))
375
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
383
384 def test_shr(self):
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))
388
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
396
397 def test_lt(self):
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))
401
402 def test_le(self):
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))
406
407 def test_gt(self):
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))
411
412 def test_ge(self):
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))
416
417 def test_eq(self):
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))
421
422 def test_ne(self):
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))
426
427 def test_mux(self):
428 s = Const(0)
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))
438
439 def test_mux_wide(self):
440 s = Const(0b100)
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))")
443
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))")
447
448 def test_bool(self):
449 v = Const(0).bool()
450 self.assertEqual(repr(v), "(b (const 1'd0))")
451 self.assertEqual(v.shape(), unsigned(1))
452
453 def test_any(self):
454 v = Const(0b101).any()
455 self.assertEqual(repr(v), "(r| (const 3'd5))")
456
457 def test_all(self):
458 v = Const(0b101).all()
459 self.assertEqual(repr(v), "(r& (const 3'd5))")
460
461 def test_xor(self):
462 v = Const(0b101).xor()
463 self.assertEqual(repr(v), "(r^ (const 3'd5))")
464
465 def test_matches(self):
466 s = Signal(4)
467 self.assertRepr(s.matches(), "(const 1'd0)")
468 self.assertRepr(s.matches(1), """
469 (== (sig s) (const 1'd1))
470 """)
471 self.assertRepr(s.matches(0, 1), """
472 (r| (cat (== (sig s) (const 1'd0)) (== (sig s) (const 1'd1))))
473 """)
474 self.assertRepr(s.matches("10--"), """
475 (== (& (sig s) (const 4'd12)) (const 4'd8))
476 """)
477 self.assertRepr(s.matches("1 0--"), """
478 (== (& (sig s) (const 4'd12)) (const 4'd8))
479 """)
480
481 def test_matches_enum(self):
482 s = Signal(SignedEnum)
483 self.assertRepr(s.matches(SignedEnum.FOO), """
484 (== (sig s) (const 1'sd-1))
485 """)
486
487 def test_matches_width_wrong(self):
488 s = Signal(4)
489 with self.assertRaises(SyntaxError,
490 msg="Match pattern '--' must have the same width as match value (which is 4)"):
491 s.matches("--")
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"):
495 s.matches(0b10110)
496
497 def test_matches_bits_wrong(self):
498 s = Signal(4)
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"):
502 s.matches("abc")
503
504 def test_matches_pattern_wrong(self):
505 s = Signal(4)
506 with self.assertRaises(SyntaxError,
507 msg="Match pattern must be an integer, a string, or an enumeration, not 1.0"):
508 s.matches(1.0)
509
510 def test_hash(self):
511 with self.assertRaises(TypeError):
512 hash(Const(0) + Const(0))
513
514
515 class SliceTestCase(FHDLTestCase):
516 def test_shape(self):
517 s1 = Const(10)[2]
518 self.assertEqual(s1.shape(), unsigned(1))
519 self.assertIsInstance(s1.shape(), Shape)
520 s2 = Const(-10)[0:2]
521 self.assertEqual(s2.shape(), unsigned(2))
522
523 def test_start_end_negative(self):
524 c = Const(0, 8)
525 s1 = Slice(c, 0, -1)
526 self.assertEqual((s1.start, s1.stop), (0, 7))
527 s1 = Slice(c, -4, -1)
528 self.assertEqual((s1.start, s1.stop), (4, 7))
529
530 def test_start_end_wrong(self):
531 with self.assertRaises(TypeError,
532 msg="Slice start must be an integer, not 'x'"):
533 Slice(0, "x", 1)
534 with self.assertRaises(TypeError,
535 msg="Slice stop must be an integer, not 'x'"):
536 Slice(0, 1, "x")
537
538 def test_start_end_out_of_range(self):
539 c = Const(0, 8)
540 with self.assertRaises(IndexError,
541 msg="Cannot start slice 10 bits into 8-bit value"):
542 Slice(c, 10, 12)
543 with self.assertRaises(IndexError,
544 msg="Cannot stop slice 12 bits into 8-bit value"):
545 Slice(c, 0, 12)
546 with self.assertRaises(IndexError,
547 msg="Slice start 4 must be less than slice stop 2"):
548 Slice(c, 4, 2)
549
550 def test_repr(self):
551 s1 = Const(10)[2]
552 self.assertEqual(repr(s1), "(slice (const 4'd10) 2:3)")
553
554
555 class BitSelectTestCase(FHDLTestCase):
556 def setUp(self):
557 self.c = Const(0, 8)
558 self.s = Signal(range(self.c.width))
559
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))
568
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)
573
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)""")
578
579 def test_width_wrong(self):
580 with self.assertRaises(TypeError):
581 self.c.bit_select(self.s, -1)
582
583 def test_repr(self):
584 s = self.c.bit_select(self.s, 2)
585 self.assertEqual(repr(s), "(part (const 8'd0) (sig s) 2 1)")
586
587
588 class WordSelectTestCase(FHDLTestCase):
589 def setUp(self):
590 self.c = Const(0, 8)
591 self.s = Signal(range(self.c.width))
592
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)
598
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)
603
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)""")
608
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)
614
615 def test_repr(self):
616 s = self.c.word_select(self.s, 2)
617 self.assertEqual(repr(s), "(part (const 8'd0) (sig s) 2 2)")
618
619
620 class CatTestCase(FHDLTestCase):
621 def test_shape(self):
622 c0 = Cat()
623 self.assertEqual(c0.shape(), unsigned(0))
624 self.assertIsInstance(c0.shape(), Shape)
625 c1 = Cat(Const(10))
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))
631
632 def test_repr(self):
633 c1 = Cat(Const(10), Const(1))
634 self.assertEqual(repr(c1), "(cat (const 4'd10) (const 1'd1))")
635
636
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))
644
645 def test_count_wrong(self):
646 with self.assertRaises(TypeError):
647 Repl(Const(10), -1)
648 with self.assertRaises(TypeError):
649 Repl(Const(10), "str")
650
651 def test_repr(self):
652 s = Repl(Const(10), 3)
653 self.assertEqual(repr(s), "(repl (const 4'd10) 3)")
654
655
656 class ArrayTestCase(FHDLTestCase):
657 def test_acts_like_array(self):
658 a = Array([1,2,3])
659 self.assertSequenceEqual(a, [1,2,3])
660 self.assertEqual(a[1], 2)
661 a[1] = 4
662 self.assertSequenceEqual(a, [1,4,3])
663 del a[1]
664 self.assertSequenceEqual(a, [1,3])
665 a.insert(1, 2)
666 self.assertSequenceEqual(a, [1,2,3])
667
668 def test_becomes_immutable(self):
669 a = Array([1,2,3])
670 s1 = Signal(range(len(a)))
671 s2 = Signal(range(len(a)))
672 v1 = a[s1]
673 v2 = a[s2]
674 with self.assertRaisesRegex(ValueError,
675 regex=r"^Array can no longer be mutated after it was indexed with a value at "):
676 a[1] = 2
677 with self.assertRaisesRegex(ValueError,
678 regex=r"^Array can no longer be mutated after it was indexed with a value at "):
679 del a[1]
680 with self.assertRaisesRegex(ValueError,
681 regex=r"^Array can no longer be mutated after it was indexed with a value at "):
682 a.insert(1, 2)
683
684 def test_repr(self):
685 a = Array([1,2,3])
686 self.assertEqual(repr(a), "(array mutable [1, 2, 3])")
687 s = Signal(range(len(a)))
688 v = a[s]
689 self.assertEqual(repr(a), "(array [1, 2, 3])")
690
691
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))
695 a = Signal(range(3))
696 b = Signal(range(3))
697 v = m[a][b]
698 self.assertEqual(v.shape(), unsigned(4))
699
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)))
705 v = a[s]
706 self.assertEqual(v.p.shape(), unsigned(4))
707 self.assertEqual(v.n.shape(), signed(6))
708
709 def test_repr(self):
710 a = Array([1, 2, 3])
711 s = Signal(range(3))
712 v = a[s]
713 self.assertEqual(repr(v), "(proxy (array [1, 2, 3]) (sig s))")
714
715
716 class SignalTestCase(FHDLTestCase):
717 def test_shape(self):
718 s1 = Signal()
719 self.assertEqual(s1.shape(), unsigned(1))
720 self.assertIsInstance(s1.shape(), Shape)
721 s2 = Signal(2)
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))
727 s5 = Signal(0)
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))
741
742 def test_shape_wrong(self):
743 with self.assertRaises(TypeError,
744 msg="Width must be a non-negative integer, not -10"):
745 Signal(-10)
746
747 def test_name(self):
748 s1 = Signal()
749 self.assertEqual(s1.name, "s1")
750 s2 = Signal(name="sig")
751 self.assertEqual(s2.name, "sig")
752
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)
757
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"
763 ):
764 Signal(1, reset=StringEnum.FOO)
765
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"):
769 Signal(3, reset=8)
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)
776
777 def test_attrs(self):
778 s1 = Signal()
779 self.assertEqual(s1.attrs, {})
780 s2 = Signal(attrs={"no_retiming": True})
781 self.assertEqual(s2.attrs, {"no_retiming": True})
782
783 def test_repr(self):
784 s1 = Signal()
785 self.assertEqual(repr(s1), "(sig s1)")
786
787 def test_like(self):
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)
799 s6 = Signal.like(10)
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")
805
806 def test_decoder(self):
807 class Color(Enum):
808 RED = 1
809 BLUE = 2
810 s = Signal(decoder=Color)
811 self.assertEqual(s.decoder(1), "RED/1")
812 self.assertEqual(s.decoder(3), "3")
813
814 def test_enum(self):
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")
820
821
822 class ClockSignalTestCase(FHDLTestCase):
823 def test_domain(self):
824 s1 = ClockSignal()
825 self.assertEqual(s1.domain, "sync")
826 s2 = ClockSignal("pix")
827 self.assertEqual(s2.domain, "pix")
828
829 with self.assertRaises(TypeError,
830 msg="Clock domain name must be a string, not 1"):
831 ClockSignal(1)
832
833 def test_shape(self):
834 s1 = ClockSignal()
835 self.assertEqual(s1.shape(), unsigned(1))
836 self.assertIsInstance(s1.shape(), Shape)
837
838 def test_repr(self):
839 s1 = ClockSignal()
840 self.assertEqual(repr(s1), "(clk sync)")
841
842 def test_wrong_name_comb(self):
843 with self.assertRaises(ValueError,
844 msg="Domain 'comb' does not have a clock"):
845 ClockSignal("comb")
846
847
848 class ResetSignalTestCase(FHDLTestCase):
849 def test_domain(self):
850 s1 = ResetSignal()
851 self.assertEqual(s1.domain, "sync")
852 s2 = ResetSignal("pix")
853 self.assertEqual(s2.domain, "pix")
854
855 with self.assertRaises(TypeError,
856 msg="Clock domain name must be a string, not 1"):
857 ResetSignal(1)
858
859 def test_shape(self):
860 s1 = ResetSignal()
861 self.assertEqual(s1.shape(), unsigned(1))
862 self.assertIsInstance(s1.shape(), Shape)
863
864 def test_repr(self):
865 s1 = ResetSignal()
866 self.assertEqual(repr(s1), "(rst sync)")
867
868 def test_wrong_name_comb(self):
869 with self.assertRaises(ValueError,
870 msg="Domain 'comb' does not have a reset"):
871 ResetSignal("comb")
872
873
874 class MockUserValue(UserValue):
875 def __init__(self, lowered):
876 super().__init__()
877 self.lower_count = 0
878 self.lowered = lowered
879
880 def lower(self):
881 self.lower_count += 1
882 return self.lowered
883
884
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)
890 uv.lowered = 2
891 self.assertEqual(uv.shape(), unsigned(1))
892 self.assertEqual(uv.lower_count, 1)
893
894
895 class SampleTestCase(FHDLTestCase):
896 def test_const(self):
897 s = Sample(1, 1, "sync")
898 self.assertEqual(s.shape(), unsigned(1))
899
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")
905
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")
911
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")
916
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)
921
922
923 class InitialTestCase(FHDLTestCase):
924 def test_initial(self):
925 i = Initial()
926 self.assertEqual(i.shape(), unsigned(1))