hdl.ast: make Signal(name=) a keyword-only argument.
[nmigen.git] / nmigen / test / test_hdl_ast.py
1 import warnings
2 from enum import Enum
3
4 from ..hdl.ast import *
5 from .tools 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 ValueTestCase(FHDLTestCase):
26 def test_wrap(self):
27 self.assertIsInstance(Value.wrap(0), Const)
28 self.assertIsInstance(Value.wrap(True), Const)
29 c = Const(0)
30 self.assertIs(Value.wrap(c), c)
31 with self.assertRaises(TypeError,
32 msg="Object ''str'' is not an nMigen value"):
33 Value.wrap("str")
34
35 def test_wrap_enum(self):
36 e1 = Value.wrap(UnsignedEnum.FOO)
37 self.assertIsInstance(e1, Const)
38 self.assertEqual(e1.shape(), (2, False))
39 e2 = Value.wrap(SignedEnum.FOO)
40 self.assertIsInstance(e2, Const)
41 self.assertEqual(e2.shape(), (2, True))
42
43 def test_wrap_enum_wrong(self):
44 with self.assertRaises(TypeError,
45 msg="Only enumerations with integer values can be converted to nMigen values"):
46 Value.wrap(StringEnum.FOO)
47
48 def test_bool(self):
49 with self.assertRaises(TypeError,
50 msg="Attempted to convert nMigen value to boolean"):
51 if Const(0):
52 pass
53
54 def test_len(self):
55 self.assertEqual(len(Const(10)), 4)
56
57 def test_getitem_int(self):
58 s1 = Const(10)[0]
59 self.assertIsInstance(s1, Slice)
60 self.assertEqual(s1.start, 0)
61 self.assertEqual(s1.end, 1)
62 s2 = Const(10)[-1]
63 self.assertIsInstance(s2, Slice)
64 self.assertEqual(s2.start, 3)
65 self.assertEqual(s2.end, 4)
66 with self.assertRaises(IndexError,
67 msg="Cannot index 5 bits into 4-bit value"):
68 Const(10)[5]
69
70 def test_getitem_slice(self):
71 s1 = Const(10)[1:3]
72 self.assertIsInstance(s1, Slice)
73 self.assertEqual(s1.start, 1)
74 self.assertEqual(s1.end, 3)
75 s2 = Const(10)[1:-2]
76 self.assertIsInstance(s2, Slice)
77 self.assertEqual(s2.start, 1)
78 self.assertEqual(s2.end, 2)
79 s3 = Const(31)[::2]
80 self.assertIsInstance(s3, Cat)
81 self.assertIsInstance(s3.parts[0], Slice)
82 self.assertEqual(s3.parts[0].start, 0)
83 self.assertEqual(s3.parts[0].end, 1)
84 self.assertIsInstance(s3.parts[1], Slice)
85 self.assertEqual(s3.parts[1].start, 2)
86 self.assertEqual(s3.parts[1].end, 3)
87 self.assertIsInstance(s3.parts[2], Slice)
88 self.assertEqual(s3.parts[2].start, 4)
89 self.assertEqual(s3.parts[2].end, 5)
90
91 def test_getitem_wrong(self):
92 with self.assertRaises(TypeError,
93 msg="Cannot index value with 'str'"):
94 Const(31)["str"]
95
96
97 class ConstTestCase(FHDLTestCase):
98 def test_shape(self):
99 self.assertEqual(Const(0).shape(), (1, False))
100 self.assertEqual(Const(1).shape(), (1, False))
101 self.assertEqual(Const(10).shape(), (4, False))
102 self.assertEqual(Const(-10).shape(), (5, True))
103
104 self.assertEqual(Const(1, 4).shape(), (4, False))
105 self.assertEqual(Const(1, (4, True)).shape(), (4, True))
106 self.assertEqual(Const(0, (0, False)).shape(), (0, False))
107
108 def test_shape_bad(self):
109 with self.assertRaises(TypeError,
110 msg="Width must be a non-negative integer, not '-1'"):
111 Const(1, -1)
112
113 def test_normalization(self):
114 self.assertEqual(Const(0b10110, (5, True)).value, -10)
115
116 def test_value(self):
117 self.assertEqual(Const(10).value, 10)
118
119 def test_repr(self):
120 self.assertEqual(repr(Const(10)), "(const 4'd10)")
121 self.assertEqual(repr(Const(-10)), "(const 5'sd-10)")
122
123 def test_hash(self):
124 with self.assertRaises(TypeError):
125 hash(Const(0))
126
127
128 class OperatorTestCase(FHDLTestCase):
129 def test_bool(self):
130 v = Const(0, 4).bool()
131 self.assertEqual(repr(v), "(b (const 4'd0))")
132 self.assertEqual(v.shape(), (1, False))
133
134 def test_invert(self):
135 v = ~Const(0, 4)
136 self.assertEqual(repr(v), "(~ (const 4'd0))")
137 self.assertEqual(v.shape(), (4, False))
138
139 def test_neg(self):
140 v1 = -Const(0, (4, False))
141 self.assertEqual(repr(v1), "(- (const 4'd0))")
142 self.assertEqual(v1.shape(), (5, True))
143 v2 = -Const(0, (4, True))
144 self.assertEqual(repr(v2), "(- (const 4'sd0))")
145 self.assertEqual(v2.shape(), (4, True))
146
147 def test_add(self):
148 v1 = Const(0, (4, False)) + Const(0, (6, False))
149 self.assertEqual(repr(v1), "(+ (const 4'd0) (const 6'd0))")
150 self.assertEqual(v1.shape(), (7, False))
151 v2 = Const(0, (4, True)) + Const(0, (6, True))
152 self.assertEqual(v2.shape(), (7, True))
153 v3 = Const(0, (4, True)) + Const(0, (4, False))
154 self.assertEqual(v3.shape(), (6, True))
155 v4 = Const(0, (4, False)) + Const(0, (4, True))
156 self.assertEqual(v4.shape(), (6, True))
157 v5 = 10 + Const(0, 4)
158 self.assertEqual(v5.shape(), (5, False))
159
160 def test_sub(self):
161 v1 = Const(0, (4, False)) - Const(0, (6, False))
162 self.assertEqual(repr(v1), "(- (const 4'd0) (const 6'd0))")
163 self.assertEqual(v1.shape(), (7, False))
164 v2 = Const(0, (4, True)) - Const(0, (6, True))
165 self.assertEqual(v2.shape(), (7, True))
166 v3 = Const(0, (4, True)) - Const(0, (4, False))
167 self.assertEqual(v3.shape(), (6, True))
168 v4 = Const(0, (4, False)) - Const(0, (4, True))
169 self.assertEqual(v4.shape(), (6, True))
170 v5 = 10 - Const(0, 4)
171 self.assertEqual(v5.shape(), (5, False))
172
173 def test_mul(self):
174 v1 = Const(0, (4, False)) * Const(0, (6, False))
175 self.assertEqual(repr(v1), "(* (const 4'd0) (const 6'd0))")
176 self.assertEqual(v1.shape(), (10, False))
177 v2 = Const(0, (4, True)) * Const(0, (6, True))
178 self.assertEqual(v2.shape(), (10, True))
179 v3 = Const(0, (4, True)) * Const(0, (4, False))
180 self.assertEqual(v3.shape(), (8, True))
181 v5 = 10 * Const(0, 4)
182 self.assertEqual(v5.shape(), (8, False))
183
184 def test_and(self):
185 v1 = Const(0, (4, False)) & Const(0, (6, False))
186 self.assertEqual(repr(v1), "(& (const 4'd0) (const 6'd0))")
187 self.assertEqual(v1.shape(), (6, False))
188 v2 = Const(0, (4, True)) & Const(0, (6, True))
189 self.assertEqual(v2.shape(), (6, True))
190 v3 = Const(0, (4, True)) & Const(0, (4, False))
191 self.assertEqual(v3.shape(), (5, True))
192 v4 = Const(0, (4, False)) & Const(0, (4, True))
193 self.assertEqual(v4.shape(), (5, True))
194 v5 = 10 & Const(0, 4)
195 self.assertEqual(v5.shape(), (4, False))
196
197 def test_or(self):
198 v1 = Const(0, (4, False)) | Const(0, (6, False))
199 self.assertEqual(repr(v1), "(| (const 4'd0) (const 6'd0))")
200 self.assertEqual(v1.shape(), (6, False))
201 v2 = Const(0, (4, True)) | Const(0, (6, True))
202 self.assertEqual(v2.shape(), (6, True))
203 v3 = Const(0, (4, True)) | Const(0, (4, False))
204 self.assertEqual(v3.shape(), (5, True))
205 v4 = Const(0, (4, False)) | Const(0, (4, True))
206 self.assertEqual(v4.shape(), (5, True))
207 v5 = 10 | Const(0, 4)
208 self.assertEqual(v5.shape(), (4, False))
209
210 def test_xor(self):
211 v1 = Const(0, (4, False)) ^ Const(0, (6, False))
212 self.assertEqual(repr(v1), "(^ (const 4'd0) (const 6'd0))")
213 self.assertEqual(v1.shape(), (6, False))
214 v2 = Const(0, (4, True)) ^ Const(0, (6, True))
215 self.assertEqual(v2.shape(), (6, True))
216 v3 = Const(0, (4, True)) ^ Const(0, (4, False))
217 self.assertEqual(v3.shape(), (5, True))
218 v4 = Const(0, (4, False)) ^ Const(0, (4, True))
219 self.assertEqual(v4.shape(), (5, True))
220 v5 = 10 ^ Const(0, 4)
221 self.assertEqual(v5.shape(), (4, False))
222
223 def test_shl(self):
224 v1 = Const(1, 4) << Const(4)
225 self.assertEqual(repr(v1), "(<< (const 4'd1) (const 3'd4))")
226 self.assertEqual(v1.shape(), (11, False))
227 v2 = Const(1, 4) << Const(-3)
228 self.assertEqual(v2.shape(), (7, False))
229
230 def test_shr(self):
231 v1 = Const(1, 4) >> Const(4)
232 self.assertEqual(repr(v1), "(>> (const 4'd1) (const 3'd4))")
233 self.assertEqual(v1.shape(), (4, False))
234 v2 = Const(1, 4) >> Const(-3)
235 self.assertEqual(v2.shape(), (8, False))
236
237 def test_lt(self):
238 v = Const(0, 4) < Const(0, 6)
239 self.assertEqual(repr(v), "(< (const 4'd0) (const 6'd0))")
240 self.assertEqual(v.shape(), (1, False))
241
242 def test_le(self):
243 v = Const(0, 4) <= Const(0, 6)
244 self.assertEqual(repr(v), "(<= (const 4'd0) (const 6'd0))")
245 self.assertEqual(v.shape(), (1, False))
246
247 def test_gt(self):
248 v = Const(0, 4) > Const(0, 6)
249 self.assertEqual(repr(v), "(> (const 4'd0) (const 6'd0))")
250 self.assertEqual(v.shape(), (1, False))
251
252 def test_ge(self):
253 v = Const(0, 4) >= Const(0, 6)
254 self.assertEqual(repr(v), "(>= (const 4'd0) (const 6'd0))")
255 self.assertEqual(v.shape(), (1, False))
256
257 def test_eq(self):
258 v = Const(0, 4) == Const(0, 6)
259 self.assertEqual(repr(v), "(== (const 4'd0) (const 6'd0))")
260 self.assertEqual(v.shape(), (1, False))
261
262 def test_ne(self):
263 v = Const(0, 4) != Const(0, 6)
264 self.assertEqual(repr(v), "(!= (const 4'd0) (const 6'd0))")
265 self.assertEqual(v.shape(), (1, False))
266
267 def test_mux(self):
268 s = Const(0)
269 v1 = Mux(s, Const(0, (4, False)), Const(0, (6, False)))
270 self.assertEqual(repr(v1), "(m (const 1'd0) (const 4'd0) (const 6'd0))")
271 self.assertEqual(v1.shape(), (6, False))
272 v2 = Mux(s, Const(0, (4, True)), Const(0, (6, True)))
273 self.assertEqual(v2.shape(), (6, True))
274 v3 = Mux(s, Const(0, (4, True)), Const(0, (4, False)))
275 self.assertEqual(v3.shape(), (5, True))
276 v4 = Mux(s, Const(0, (4, False)), Const(0, (4, True)))
277 self.assertEqual(v4.shape(), (5, True))
278
279 def test_bool(self):
280 v = Const(0).bool()
281 self.assertEqual(repr(v), "(b (const 1'd0))")
282 self.assertEqual(v.shape(), (1, False))
283
284 def test_any(self):
285 v = Const(0b101).any()
286 self.assertEqual(repr(v), "(r| (const 3'd5))")
287
288 def test_all(self):
289 v = Const(0b101).all()
290 self.assertEqual(repr(v), "(r& (const 3'd5))")
291
292 def test_xor(self):
293 v = Const(0b101).xor()
294 self.assertEqual(repr(v), "(r^ (const 3'd5))")
295
296 def test_matches(self):
297 s = Signal(4)
298 self.assertRepr(s.matches(), "(const 1'd0)")
299 self.assertRepr(s.matches(1), """
300 (== (sig s) (const 1'd1))
301 """)
302 self.assertRepr(s.matches(0, 1), """
303 (r| (cat (== (sig s) (const 1'd0)) (== (sig s) (const 1'd1))))
304 """)
305 self.assertRepr(s.matches("10--"), """
306 (== (& (sig s) (const 4'd12)) (const 4'd8))
307 """)
308
309 def test_matches_enum(self):
310 s = Signal.enum(SignedEnum)
311 self.assertRepr(s.matches(SignedEnum.FOO), """
312 (== (& (sig s) (const 2'd3)) (const 2'd3))
313 """)
314
315 def test_matches_width_wrong(self):
316 s = Signal(4)
317 with self.assertRaises(SyntaxError,
318 msg="Match pattern '--' must have the same width as match value (which is 4)"):
319 s.matches("--")
320 with self.assertWarns(SyntaxWarning,
321 msg="Match pattern '10110' is wider than match value (which has width 4); "
322 "comparison will never be true"):
323 s.matches(0b10110)
324
325 def test_matches_bits_wrong(self):
326 s = Signal(4)
327 with self.assertRaises(SyntaxError,
328 msg="Match pattern 'abc' must consist of 0, 1, and - (don't care) bits"):
329 s.matches("abc")
330
331 def test_matches_pattern_wrong(self):
332 s = Signal(4)
333 with self.assertRaises(SyntaxError,
334 msg="Match pattern must be an integer, a string, or an enumeration, not 1.0"):
335 s.matches(1.0)
336
337 def test_hash(self):
338 with self.assertRaises(TypeError):
339 hash(Const(0) + Const(0))
340
341
342 class SliceTestCase(FHDLTestCase):
343 def test_shape(self):
344 s1 = Const(10)[2]
345 self.assertEqual(s1.shape(), (1, False))
346 s2 = Const(-10)[0:2]
347 self.assertEqual(s2.shape(), (2, False))
348
349 def test_start_end_negative(self):
350 c = Const(0, 8)
351 s1 = Slice(c, 0, -1)
352 self.assertEqual((s1.start, s1.end), (0, 7))
353 s1 = Slice(c, -4, -1)
354 self.assertEqual((s1.start, s1.end), (4, 7))
355
356 def test_start_end_wrong(self):
357 with self.assertRaises(TypeError,
358 msg="Slice start must be an integer, not ''x''"):
359 Slice(0, "x", 1)
360 with self.assertRaises(TypeError,
361 msg="Slice end must be an integer, not ''x''"):
362 Slice(0, 1, "x")
363
364 def test_start_end_out_of_range(self):
365 c = Const(0, 8)
366 with self.assertRaises(IndexError,
367 msg="Cannot start slice 10 bits into 8-bit value"):
368 Slice(c, 10, 12)
369 with self.assertRaises(IndexError,
370 msg="Cannot end slice 12 bits into 8-bit value"):
371 Slice(c, 0, 12)
372 with self.assertRaises(IndexError,
373 msg="Slice start 4 must be less than slice end 2"):
374 Slice(c, 4, 2)
375
376 def test_repr(self):
377 s1 = Const(10)[2]
378 self.assertEqual(repr(s1), "(slice (const 4'd10) 2:3)")
379
380
381 class BitSelectTestCase(FHDLTestCase):
382 def setUp(self):
383 self.c = Const(0, 8)
384 self.s = Signal.range(self.c.width)
385
386 def test_shape(self):
387 s1 = self.c.bit_select(self.s, 2)
388 self.assertEqual(s1.shape(), (2, False))
389 s2 = self.c.bit_select(self.s, 0)
390 self.assertEqual(s2.shape(), (0, False))
391
392 def test_stride(self):
393 s1 = self.c.bit_select(self.s, 2)
394 self.assertEqual(s1.stride, 1)
395
396 def test_width_bad(self):
397 with self.assertRaises(TypeError):
398 self.c.bit_select(self.s, -1)
399
400 def test_repr(self):
401 s = self.c.bit_select(self.s, 2)
402 self.assertEqual(repr(s), "(part (const 8'd0) (sig s) 2 1)")
403
404
405 class WordSelectTestCase(FHDLTestCase):
406 def setUp(self):
407 self.c = Const(0, 8)
408 self.s = Signal.range(self.c.width)
409
410 def test_shape(self):
411 s1 = self.c.word_select(self.s, 2)
412 self.assertEqual(s1.shape(), (2, False))
413
414 def test_stride(self):
415 s1 = self.c.word_select(self.s, 2)
416 self.assertEqual(s1.stride, 2)
417
418 def test_width_bad(self):
419 with self.assertRaises(TypeError):
420 self.c.word_select(self.s, 0)
421 with self.assertRaises(TypeError):
422 self.c.word_select(self.s, -1)
423
424 def test_repr(self):
425 s = self.c.word_select(self.s, 2)
426 self.assertEqual(repr(s), "(part (const 8'd0) (sig s) 2 2)")
427
428
429 class CatTestCase(FHDLTestCase):
430 def test_shape(self):
431 c0 = Cat()
432 self.assertEqual(c0.shape(), (0, False))
433 c1 = Cat(Const(10))
434 self.assertEqual(c1.shape(), (4, False))
435 c2 = Cat(Const(10), Const(1))
436 self.assertEqual(c2.shape(), (5, False))
437 c3 = Cat(Const(10), Const(1), Const(0))
438 self.assertEqual(c3.shape(), (6, False))
439
440 def test_repr(self):
441 c1 = Cat(Const(10), Const(1))
442 self.assertEqual(repr(c1), "(cat (const 4'd10) (const 1'd1))")
443
444
445 class ReplTestCase(FHDLTestCase):
446 def test_shape(self):
447 s1 = Repl(Const(10), 3)
448 self.assertEqual(s1.shape(), (12, False))
449 s2 = Repl(Const(10), 0)
450 self.assertEqual(s2.shape(), (0, False))
451
452 def test_count_wrong(self):
453 with self.assertRaises(TypeError):
454 Repl(Const(10), -1)
455 with self.assertRaises(TypeError):
456 Repl(Const(10), "str")
457
458 def test_repr(self):
459 s = Repl(Const(10), 3)
460 self.assertEqual(repr(s), "(repl (const 4'd10) 3)")
461
462
463 class ArrayTestCase(FHDLTestCase):
464 def test_acts_like_array(self):
465 a = Array([1,2,3])
466 self.assertSequenceEqual(a, [1,2,3])
467 self.assertEqual(a[1], 2)
468 a[1] = 4
469 self.assertSequenceEqual(a, [1,4,3])
470 del a[1]
471 self.assertSequenceEqual(a, [1,3])
472 a.insert(1, 2)
473 self.assertSequenceEqual(a, [1,2,3])
474
475 def test_becomes_immutable(self):
476 a = Array([1,2,3])
477 s1 = Signal.range(len(a))
478 s2 = Signal.range(len(a))
479 v1 = a[s1]
480 v2 = a[s2]
481 with self.assertRaisesRegex(ValueError,
482 regex=r"^Array can no longer be mutated after it was indexed with a value at "):
483 a[1] = 2
484 with self.assertRaisesRegex(ValueError,
485 regex=r"^Array can no longer be mutated after it was indexed with a value at "):
486 del a[1]
487 with self.assertRaisesRegex(ValueError,
488 regex=r"^Array can no longer be mutated after it was indexed with a value at "):
489 a.insert(1, 2)
490
491 def test_repr(self):
492 a = Array([1,2,3])
493 self.assertEqual(repr(a), "(array mutable [1, 2, 3])")
494 s = Signal.range(len(a))
495 v = a[s]
496 self.assertEqual(repr(a), "(array [1, 2, 3])")
497
498
499 class ArrayProxyTestCase(FHDLTestCase):
500 def test_index_shape(self):
501 m = Array(Array(x * y for y in range(1, 4)) for x in range(1, 4))
502 a = Signal.range(3)
503 b = Signal.range(3)
504 v = m[a][b]
505 self.assertEqual(v.shape(), (4, False))
506
507 def test_attr_shape(self):
508 from collections import namedtuple
509 pair = namedtuple("pair", ("p", "n"))
510 a = Array(pair(i, -i) for i in range(10))
511 s = Signal.range(len(a))
512 v = a[s]
513 self.assertEqual(v.p.shape(), (4, False))
514 self.assertEqual(v.n.shape(), (6, True))
515
516 def test_repr(self):
517 a = Array([1, 2, 3])
518 s = Signal.range(3)
519 v = a[s]
520 self.assertEqual(repr(v), "(proxy (array [1, 2, 3]) (sig s))")
521
522
523 class SignalTestCase(FHDLTestCase):
524 def test_shape(self):
525 s1 = Signal()
526 self.assertEqual(s1.shape(), (1, False))
527 s2 = Signal(2)
528 self.assertEqual(s2.shape(), (2, False))
529 s3 = Signal((2, False))
530 self.assertEqual(s3.shape(), (2, False))
531 s4 = Signal((2, True))
532 self.assertEqual(s4.shape(), (2, True))
533 s5 = Signal(0)
534 self.assertEqual(s5.shape(), (0, False))
535 s6 = Signal.range(16)
536 self.assertEqual(s6.shape(), (4, False))
537 s7 = Signal.range(4, 16)
538 self.assertEqual(s7.shape(), (4, False))
539 s8 = Signal.range(-4, 16)
540 self.assertEqual(s8.shape(), (5, True))
541 s9 = Signal.range(-20, 16)
542 self.assertEqual(s9.shape(), (6, True))
543 s10 = Signal.range(0)
544 self.assertEqual(s10.shape(), (1, False))
545 s11 = Signal.range(1)
546 self.assertEqual(s11.shape(), (1, False))
547 # deprecated
548 with warnings.catch_warnings():
549 warnings.filterwarnings(action="ignore", category=DeprecationWarning)
550 d6 = Signal(max=16)
551 self.assertEqual(d6.shape(), (4, False))
552 d7 = Signal(min=4, max=16)
553 self.assertEqual(d7.shape(), (4, False))
554 d8 = Signal(min=-4, max=16)
555 self.assertEqual(d8.shape(), (5, True))
556 d9 = Signal(min=-20, max=16)
557 self.assertEqual(d9.shape(), (6, True))
558 d10 = Signal(max=1)
559 self.assertEqual(d10.shape(), (0, False))
560
561 def test_shape_bad(self):
562 with self.assertRaises(TypeError,
563 msg="Width must be a non-negative integer, not '-10'"):
564 Signal(-10)
565
566 def test_min_max_deprecated(self):
567 with self.assertWarns(DeprecationWarning,
568 msg="instead of `Signal(min=0, max=10)`, use `Signal.range(0, 10)`"):
569 Signal(max=10)
570 with warnings.catch_warnings():
571 warnings.filterwarnings(action="ignore", category=DeprecationWarning)
572 with self.assertRaises(ValueError,
573 msg="Lower bound 10 should be less or equal to higher bound 4"):
574 Signal(min=10, max=4)
575 with self.assertRaises(ValueError,
576 msg="Only one of bits/signedness or bounds may be specified"):
577 Signal(2, min=10)
578
579 def test_name(self):
580 s1 = Signal()
581 self.assertEqual(s1.name, "s1")
582 s2 = Signal(name="sig")
583 self.assertEqual(s2.name, "sig")
584
585 def test_reset(self):
586 s1 = Signal(4, reset=0b111, reset_less=True)
587 self.assertEqual(s1.reset, 0b111)
588 self.assertEqual(s1.reset_less, True)
589
590 def test_reset_narrow(self):
591 with self.assertWarns(SyntaxWarning,
592 msg="Reset value 8 requires 4 bits to represent, but the signal only has 3 bits"):
593 Signal(3, reset=8)
594 with self.assertWarns(SyntaxWarning,
595 msg="Reset value 4 requires 4 bits to represent, but the signal only has 3 bits"):
596 Signal((3, True), reset=4)
597 with self.assertWarns(SyntaxWarning,
598 msg="Reset value -5 requires 4 bits to represent, but the signal only has 3 bits"):
599 Signal((3, True), reset=-5)
600
601 def test_attrs(self):
602 s1 = Signal()
603 self.assertEqual(s1.attrs, {})
604 s2 = Signal(attrs={"no_retiming": True})
605 self.assertEqual(s2.attrs, {"no_retiming": True})
606
607 def test_repr(self):
608 s1 = Signal()
609 self.assertEqual(repr(s1), "(sig s1)")
610
611 def test_like(self):
612 s1 = Signal.like(Signal(4))
613 self.assertEqual(s1.shape(), (4, False))
614 s2 = Signal.like(Signal.range(-15, 1))
615 self.assertEqual(s2.shape(), (5, True))
616 s3 = Signal.like(Signal(4, reset=0b111, reset_less=True))
617 self.assertEqual(s3.reset, 0b111)
618 self.assertEqual(s3.reset_less, True)
619 s4 = Signal.like(Signal(attrs={"no_retiming": True}))
620 self.assertEqual(s4.attrs, {"no_retiming": True})
621 s5 = Signal.like(Signal(decoder=str))
622 self.assertEqual(s5.decoder, str)
623 s6 = Signal.like(10)
624 self.assertEqual(s6.shape(), (4, False))
625 s7 = [Signal.like(Signal(4))][0]
626 self.assertEqual(s7.name, "$like")
627 s8 = Signal.like(s1, name_suffix="_ff")
628 self.assertEqual(s8.name, "s1_ff")
629
630 def test_decoder(self):
631 class Color(Enum):
632 RED = 1
633 BLUE = 2
634 s = Signal(decoder=Color)
635 self.assertEqual(s.decoder(1), "RED/1")
636 self.assertEqual(s.decoder(3), "3")
637
638 def test_enum(self):
639 s1 = Signal.enum(UnsignedEnum)
640 self.assertEqual(s1.shape(), (2, False))
641 s2 = Signal.enum(SignedEnum)
642 self.assertEqual(s2.shape(), (2, True))
643 self.assertEqual(s2.decoder(SignedEnum.FOO), "FOO/-1")
644
645
646 class ClockSignalTestCase(FHDLTestCase):
647 def test_domain(self):
648 s1 = ClockSignal()
649 self.assertEqual(s1.domain, "sync")
650 s2 = ClockSignal("pix")
651 self.assertEqual(s2.domain, "pix")
652
653 with self.assertRaises(TypeError,
654 msg="Clock domain name must be a string, not '1'"):
655 ClockSignal(1)
656
657 def test_shape(self):
658 self.assertEqual(ClockSignal().shape(), (1, False))
659
660 def test_repr(self):
661 s1 = ClockSignal()
662 self.assertEqual(repr(s1), "(clk sync)")
663
664 def test_wrong_name_comb(self):
665 with self.assertRaises(ValueError,
666 msg="Domain 'comb' does not have a clock"):
667 ClockSignal("comb")
668
669
670 class ResetSignalTestCase(FHDLTestCase):
671 def test_domain(self):
672 s1 = ResetSignal()
673 self.assertEqual(s1.domain, "sync")
674 s2 = ResetSignal("pix")
675 self.assertEqual(s2.domain, "pix")
676
677 with self.assertRaises(TypeError,
678 msg="Clock domain name must be a string, not '1'"):
679 ResetSignal(1)
680
681 def test_shape(self):
682 self.assertEqual(ResetSignal().shape(), (1, False))
683
684 def test_repr(self):
685 s1 = ResetSignal()
686 self.assertEqual(repr(s1), "(rst sync)")
687
688 def test_wrong_name_comb(self):
689 with self.assertRaises(ValueError,
690 msg="Domain 'comb' does not have a reset"):
691 ResetSignal("comb")
692
693
694 class MockUserValue(UserValue):
695 def __init__(self, lowered):
696 super().__init__()
697 self.lower_count = 0
698 self.lowered = lowered
699
700 def lower(self):
701 self.lower_count += 1
702 return self.lowered
703
704
705 class UserValueTestCase(FHDLTestCase):
706 def test_shape(self):
707 uv = MockUserValue(1)
708 self.assertEqual(uv.shape(), (1, False))
709 uv.lowered = 2
710 self.assertEqual(uv.shape(), (1, False))
711 self.assertEqual(uv.lower_count, 1)
712
713
714 class SampleTestCase(FHDLTestCase):
715 def test_const(self):
716 s = Sample(1, 1, "sync")
717 self.assertEqual(s.shape(), (1, False))
718
719 def test_signal(self):
720 s1 = Sample(Signal(2), 1, "sync")
721 self.assertEqual(s1.shape(), (2, False))
722 s2 = Sample(ClockSignal(), 1, "sync")
723 s3 = Sample(ResetSignal(), 1, "sync")
724
725 def test_wrong_value_operator(self):
726 with self.assertRaises(TypeError,
727 "Sampled value must be a signal or a constant, not "
728 "(+ (sig $signal) (const 1'd1))"):
729 Sample(Signal() + 1, 1, "sync")
730
731 def test_wrong_clocks_neg(self):
732 with self.assertRaises(ValueError,
733 "Cannot sample a value 1 cycles in the future"):
734 Sample(Signal(), -1, "sync")
735
736 def test_wrong_domain(self):
737 with self.assertRaises(TypeError,
738 "Domain name must be a string or None, not 0"):
739 Sample(Signal(), 1, 0)
740
741
742 class InitialTestCase(FHDLTestCase):
743 def test_initial(self):
744 i = Initial()
745 self.assertEqual(i.shape(), (1, False))