3 from ..hdl
.ast
import *
4 from ..hdl
.rec
import *
8 class UnsignedEnum(Enum
):
14 class LayoutTestCase(FHDLTestCase
):
15 def test_fields(self
):
16 layout
= Layout
.cast([
19 ("stb", 1, DIR_FANOUT
),
20 ("ack", 1, DIR_FANIN
),
27 self
.assertEqual(layout
["cyc"], ((1, False), DIR_NONE
))
28 self
.assertEqual(layout
["data"], ((32, True), DIR_NONE
))
29 self
.assertEqual(layout
["stb"], ((1, False), DIR_FANOUT
))
30 self
.assertEqual(layout
["ack"], ((1, False), DIR_FANIN
))
31 sublayout
= layout
["info"][0]
32 self
.assertEqual(layout
["info"][1], DIR_NONE
)
33 self
.assertEqual(sublayout
["a"], ((1, False), DIR_NONE
))
34 self
.assertEqual(sublayout
["b"], ((1, False), DIR_NONE
))
36 def test_enum_field(self
):
37 layout
= Layout
.cast([
38 ("enum", UnsignedEnum
),
39 ("enum_dir", UnsignedEnum
, DIR_FANOUT
),
41 self
.assertEqual(layout
["enum"], ((2, False), DIR_NONE
))
42 self
.assertEqual(layout
["enum_dir"], ((2, False), DIR_FANOUT
))
44 def test_range_field(self
):
45 layout
= Layout
.cast([
46 ("range", range(0, 7)),
48 self
.assertEqual(layout
["range"], ((3, False), DIR_NONE
))
50 def test_slice_tuple(self
):
51 layout
= Layout
.cast([
56 expect
= Layout
.cast([
60 self
.assertEqual(layout
["a", "c"], expect
)
62 def test_wrong_field(self
):
63 with self
.assertRaises(TypeError,
64 msg
="Field (1,) has invalid layout: should be either (name, shape) or "
65 "(name, shape, direction)"):
68 def test_wrong_name(self
):
69 with self
.assertRaises(TypeError,
70 msg
="Field (1, 1) has invalid name: should be a string"):
73 def test_wrong_name_duplicate(self
):
74 with self
.assertRaises(NameError,
75 msg
="Field ('a', 2) has a name that is already present in the layout"):
76 Layout
.cast([("a", 1), ("a", 2)])
78 def test_wrong_direction(self
):
79 with self
.assertRaises(TypeError,
80 msg
="Field ('a', 1, 0) has invalid direction: should be a Direction "
81 "instance like DIR_FANIN"):
82 Layout
.cast([("a", 1, 0)])
84 def test_wrong_shape(self
):
85 with self
.assertRaises(TypeError,
86 msg
="Field ('a', 'x') has invalid shape: should be castable to Shape or "
87 "a list of fields of a nested record"):
88 Layout
.cast([("a", "x")])
91 class RecordTestCase(FHDLTestCase
):
102 self
.assertEqual(repr(r
), "(rec r stb data (rec r__info a b))")
103 self
.assertEqual(len(r
), 35)
104 self
.assertIsInstance(r
.stb
, Signal
)
105 self
.assertEqual(r
.stb
.name
, "r__stb")
106 self
.assertEqual(r
["stb"].name
, "r__stb")
108 self
.assertTrue(hasattr(r
, "stb"))
109 self
.assertFalse(hasattr(r
, "xxx"))
111 def test_unnamed(self
):
116 self
.assertEqual(repr(r
), "(rec <unnamed> stb)")
117 self
.assertEqual(r
.stb
.name
, "stb")
125 self
.assertEqual(repr(r
[0]), "(slice (rec r data stb) 0:1)")
126 self
.assertEqual(repr(r
[0:3]), "(slice (rec r data stb) 0:3)")
128 def test_wrong_field(self
):
133 with self
.assertRaises(AttributeError,
134 msg
="Record 'r' does not have a field 'en'. Did you mean one of: stb, ack?"):
136 with self
.assertRaises(AttributeError,
137 msg
="Record 'r' does not have a field 'en'. Did you mean one of: stb, ack?"):
140 def test_wrong_field_unnamed(self
):
145 with self
.assertRaises(AttributeError,
146 msg
="Unnamed record does not have a field 'en'. Did you mean one of: stb, ack?"):
149 def test_construct_with_fields(self
):
163 self
.assertIs(r
.stb
, ns
)
164 self
.assertIs(r
.info
, nr
)
167 r1
= Record([("a", 1), ("b", 2)])
169 self
.assertEqual(r1
.layout
, r2
.layout
)
170 self
.assertEqual(r2
.name
, "r2")
171 r3
= Record
.like(r1
, name
="foo")
172 self
.assertEqual(r3
.name
, "foo")
173 r4
= Record
.like(r1
, name_suffix
="foo")
174 self
.assertEqual(r4
.name
, "r1foo")
176 def test_like_modifications(self
):
177 r1
= Record([("a", 1), ("b", [("s", 1)])])
178 self
.assertEqual(r1
.a
.name
, "r1__a")
179 self
.assertEqual(r1
.b
.name
, "r1__b")
180 self
.assertEqual(r1
.b
.s
.name
, "r1__b__s")
184 self
.assertEqual(r2
.a
.reset
, 1)
185 self
.assertEqual(r2
.b
.s
.reset
, 1)
186 self
.assertEqual(r2
.a
.name
, "r2__a")
187 self
.assertEqual(r2
.b
.name
, "r2__b")
188 self
.assertEqual(r2
.b
.s
.name
, "r2__b__s")
190 def test_slice_tuple(self
):
191 r1
= Record([("a", 1), ("b", 2), ("c", 3)])
193 self
.assertEqual(r2
.layout
, Layout([("a", 1), ("c", 3)]))
194 self
.assertIs(r2
.a
, r1
.a
)
195 self
.assertIs(r2
.c
, r1
.c
)
198 class ConnectTestCase(FHDLTestCase
):
199 def setUp_flat(self
):
201 ("addr", 32, DIR_FANOUT
),
202 ("data_r", 32, DIR_FANIN
),
203 ("data_w", 32, DIR_FANIN
),
205 self
.periph_layout
= [
206 ("addr", 32, DIR_FANOUT
),
207 ("data_r", 32, DIR_FANIN
),
208 ("data_w", 32, DIR_FANIN
),
211 def setUp_nested(self
):
213 ("addr", 32, DIR_FANOUT
),
215 ("r", 32, DIR_FANIN
),
216 ("w", 32, DIR_FANIN
),
219 self
.periph_layout
= [
220 ("addr", 32, DIR_FANOUT
),
222 ("r", 32, DIR_FANIN
),
223 ("w", 32, DIR_FANIN
),
230 core
= Record(self
.core_layout
)
231 periph1
= Record(self
.periph_layout
)
232 periph2
= Record(self
.periph_layout
)
234 stmts
= core
.connect(periph1
, periph2
)
235 self
.assertRepr(stmts
, """(
236 (eq (sig periph1__addr) (sig core__addr))
237 (eq (sig periph2__addr) (sig core__addr))
238 (eq (sig core__data_r) (| (sig periph1__data_r) (sig periph2__data_r)))
239 (eq (sig core__data_w) (| (sig periph1__data_w) (sig periph2__data_w)))
242 def test_flat_include(self
):
245 core
= Record(self
.core_layout
)
246 periph1
= Record(self
.periph_layout
)
247 periph2
= Record(self
.periph_layout
)
249 stmts
= core
.connect(periph1
, periph2
, include
={"addr": True})
250 self
.assertRepr(stmts
, """(
251 (eq (sig periph1__addr) (sig core__addr))
252 (eq (sig periph2__addr) (sig core__addr))
255 def test_flat_exclude(self
):
258 core
= Record(self
.core_layout
)
259 periph1
= Record(self
.periph_layout
)
260 periph2
= Record(self
.periph_layout
)
262 stmts
= core
.connect(periph1
, periph2
, exclude
={"addr": True})
263 self
.assertRepr(stmts
, """(
264 (eq (sig core__data_r) (| (sig periph1__data_r) (sig periph2__data_r)))
265 (eq (sig core__data_w) (| (sig periph1__data_w) (sig periph2__data_w)))
268 def test_nested(self
):
271 core
= Record(self
.core_layout
)
272 periph1
= Record(self
.periph_layout
)
273 periph2
= Record(self
.periph_layout
)
275 stmts
= core
.connect(periph1
, periph2
)
277 self
.assertRepr(stmts
, """(
278 (eq (sig periph1__addr) (sig core__addr))
279 (eq (sig periph2__addr) (sig core__addr))
280 (eq (sig core__data__r) (| (sig periph1__data__r) (sig periph2__data__r)))
281 (eq (sig core__data__w) (| (sig periph1__data__w) (sig periph2__data__w)))
284 def test_wrong_include_exclude(self
):
287 core
= Record(self
.core_layout
)
288 periph
= Record(self
.periph_layout
)
290 with self
.assertRaises(AttributeError,
291 msg
="Cannot include field 'foo' because it is not present in record 'core'"):
292 core
.connect(periph
, include
={"foo": True})
294 with self
.assertRaises(AttributeError,
295 msg
="Cannot exclude field 'foo' because it is not present in record 'core'"):
296 core
.connect(periph
, exclude
={"foo": True})
298 def test_wrong_direction(self
):
299 recs
= [Record([("x", 1)]) for _
in range(2)]
301 with self
.assertRaises(TypeError,
302 msg
="Cannot connect field 'x' of unnamed record because it does not have "
304 recs
[0].connect(recs
[1])
306 def test_wrong_missing_field(self
):
307 core
= Record([("addr", 32, DIR_FANOUT
)])
310 with self
.assertRaises(AttributeError,
311 msg
="Cannot connect field 'addr' of record 'core' to subordinate record 'periph' "
312 "because the subordinate record does not have this field"):