tests: fix remove unnecessary workaround for some unittest assertions.
[nmigen.git] / nmigen / test / test_build_dsl.py
1 from collections import OrderedDict
2
3 from ..build.dsl import *
4 from .utils import *
5
6
7 class PinsTestCase(FHDLTestCase):
8 def test_basic(self):
9 p = Pins("A0 A1 A2")
10 self.assertEqual(repr(p), "(pins io A0 A1 A2)")
11 self.assertEqual(len(p.names), 3)
12 self.assertEqual(p.dir, "io")
13 self.assertEqual(p.invert, False)
14 self.assertEqual(list(p), ["A0", "A1", "A2"])
15
16 def test_invert(self):
17 p = PinsN("A0")
18 self.assertEqual(repr(p), "(pins-n io A0)")
19 self.assertEqual(p.invert, True)
20
21 def test_invert_arg(self):
22 p = Pins("A0", invert=True)
23 self.assertEqual(p.invert, True)
24
25 def test_conn(self):
26 p = Pins("0 1 2", conn=("pmod", 0))
27 self.assertEqual(list(p), ["pmod_0:0", "pmod_0:1", "pmod_0:2"])
28 p = Pins("0 1 2", conn=("pmod", "a"))
29 self.assertEqual(list(p), ["pmod_a:0", "pmod_a:1", "pmod_a:2"])
30
31 def test_map_names(self):
32 p = Pins("0 1 2", conn=("pmod", 0))
33 mapping = {
34 "pmod_0:0": "A0",
35 "pmod_0:1": "A1",
36 "pmod_0:2": "A2",
37 }
38 self.assertEqual(p.map_names(mapping, p), ["A0", "A1", "A2"])
39
40 def test_map_names_recur(self):
41 p = Pins("0", conn=("pmod", 0))
42 mapping = {
43 "pmod_0:0": "ext_0:1",
44 "ext_0:1": "A1",
45 }
46 self.assertEqual(p.map_names(mapping, p), ["A1"])
47
48 def test_wrong_names(self):
49 with self.assertRaisesRegex(TypeError,
50 r"^Names must be a whitespace-separated string, not \['A0', 'A1', 'A2'\]$"):
51 p = Pins(["A0", "A1", "A2"])
52
53 def test_wrong_dir(self):
54 with self.assertRaisesRegex(TypeError,
55 r"^Direction must be one of \"i\", \"o\", \"oe\", or \"io\", not 'wrong'$"):
56 p = Pins("A0 A1", dir="wrong")
57
58 def test_wrong_conn(self):
59 with self.assertRaisesRegex(TypeError,
60 (r"^Connector must be None or a pair of string \(connector name\) and "
61 r"integer\/string \(connector number\), not \('foo', None\)$")):
62 p = Pins("A0 A1", conn=("foo", None))
63
64 def test_wrong_map_names(self):
65 p = Pins("0 1 2", conn=("pmod", 0))
66 mapping = {
67 "pmod_0:0": "A0",
68 }
69 with self.assertRaisesRegex(NameError,
70 (r"^Resource \(pins io pmod_0:0 pmod_0:1 pmod_0:2\) refers to nonexistent "
71 r"connector pin pmod_0:1$")):
72 p.map_names(mapping, p)
73
74 def test_wrong_assert_width(self):
75 with self.assertRaisesRegex(AssertionError,
76 r"^3 names are specified \(0 1 2\), but 4 names are expected$"):
77 Pins("0 1 2", assert_width=4)
78
79
80 class DiffPairsTestCase(FHDLTestCase):
81 def test_basic(self):
82 dp = DiffPairs(p="A0 A1", n="B0 B1")
83 self.assertEqual(repr(dp), "(diffpairs io (p A0 A1) (n B0 B1))")
84 self.assertEqual(dp.p.names, ["A0", "A1"])
85 self.assertEqual(dp.n.names, ["B0", "B1"])
86 self.assertEqual(dp.dir, "io")
87 self.assertEqual(list(dp), [("A0", "B0"), ("A1", "B1")])
88
89 def test_invert(self):
90 dp = DiffPairsN(p="A0", n="B0")
91 self.assertEqual(repr(dp), "(diffpairs-n io (p A0) (n B0))")
92 self.assertEqual(dp.p.names, ["A0"])
93 self.assertEqual(dp.n.names, ["B0"])
94 self.assertEqual(dp.invert, True)
95
96 def test_conn(self):
97 dp = DiffPairs(p="0 1 2", n="3 4 5", conn=("pmod", 0))
98 self.assertEqual(list(dp), [
99 ("pmod_0:0", "pmod_0:3"),
100 ("pmod_0:1", "pmod_0:4"),
101 ("pmod_0:2", "pmod_0:5"),
102 ])
103
104 def test_dir(self):
105 dp = DiffPairs("A0", "B0", dir="o")
106 self.assertEqual(dp.dir, "o")
107 self.assertEqual(dp.p.dir, "o")
108 self.assertEqual(dp.n.dir, "o")
109
110 def test_wrong_width(self):
111 with self.assertRaisesRegex(TypeError,
112 (r"^Positive and negative pins must have the same width, but \(pins io A0\) "
113 r"and \(pins io B0 B1\) do not$")):
114 dp = DiffPairs("A0", "B0 B1")
115
116 def test_wrong_assert_width(self):
117 with self.assertRaisesRegex(AssertionError,
118 r"^3 names are specified \(0 1 2\), but 4 names are expected$"):
119 DiffPairs("0 1 2", "3 4 5", assert_width=4)
120
121
122 class AttrsTestCase(FHDLTestCase):
123 def test_basic(self):
124 a = Attrs(IO_STANDARD="LVCMOS33", PULLUP=1)
125 self.assertEqual(a["IO_STANDARD"], "LVCMOS33")
126 self.assertEqual(repr(a), "(attrs IO_STANDARD='LVCMOS33' PULLUP=1)")
127
128 def test_remove(self):
129 a = Attrs(FOO=None)
130 self.assertEqual(a["FOO"], None)
131 self.assertEqual(repr(a), "(attrs !FOO)")
132
133 def test_callable(self):
134 fn = lambda self: "FOO"
135 a = Attrs(FOO=fn)
136 self.assertEqual(a["FOO"], fn)
137 self.assertEqual(repr(a), "(attrs FOO={!r})".format(fn))
138
139 def test_wrong_value(self):
140 with self.assertRaisesRegex(TypeError,
141 r"^Value of attribute FOO must be None, int, str, or callable, not 1\.0$"):
142 a = Attrs(FOO=1.0)
143
144
145 class ClockTestCase(FHDLTestCase):
146 def test_basic(self):
147 c = Clock(1_000_000)
148 self.assertEqual(c.frequency, 1e6)
149 self.assertEqual(c.period, 1e-6)
150 self.assertEqual(repr(c), "(clock 1000000.0)")
151
152
153 class SubsignalTestCase(FHDLTestCase):
154 def test_basic_pins(self):
155 s = Subsignal("a", Pins("A0"), Attrs(IOSTANDARD="LVCMOS33"))
156 self.assertEqual(repr(s),
157 "(subsignal a (pins io A0) (attrs IOSTANDARD='LVCMOS33'))")
158
159 def test_basic_diffpairs(self):
160 s = Subsignal("a", DiffPairs("A0", "B0"))
161 self.assertEqual(repr(s),
162 "(subsignal a (diffpairs io (p A0) (n B0)))")
163
164 def test_basic_subsignals(self):
165 s = Subsignal("a",
166 Subsignal("b", Pins("A0")),
167 Subsignal("c", Pins("A1")))
168 self.assertEqual(repr(s),
169 "(subsignal a (subsignal b (pins io A0)) "
170 "(subsignal c (pins io A1)))")
171
172 def test_attrs(self):
173 s = Subsignal("a",
174 Subsignal("b", Pins("A0")),
175 Subsignal("c", Pins("A0"), Attrs(SLEW="FAST")),
176 Attrs(IOSTANDARD="LVCMOS33"))
177 self.assertEqual(s.attrs, {"IOSTANDARD": "LVCMOS33"})
178 self.assertEqual(s.ios[0].attrs, {})
179 self.assertEqual(s.ios[1].attrs, {"SLEW": "FAST"})
180
181 def test_attrs_many(self):
182 s = Subsignal("a", Pins("A0"), Attrs(SLEW="FAST"), Attrs(PULLUP="1"))
183 self.assertEqual(s.attrs, {"SLEW": "FAST", "PULLUP": "1"})
184
185 def test_clock(self):
186 s = Subsignal("a", Pins("A0"), Clock(1e6))
187 self.assertEqual(s.clock.frequency, 1e6)
188
189 def test_wrong_empty_io(self):
190 with self.assertRaisesRegex(ValueError, r"^Missing I\/O constraints$"):
191 s = Subsignal("a")
192
193 def test_wrong_io(self):
194 with self.assertRaisesRegex(TypeError,
195 (r"^Constraint must be one of Pins, DiffPairs, Subsignal, Attrs, or Clock, "
196 r"not 'wrong'$")):
197 s = Subsignal("a", "wrong")
198
199 def test_wrong_pins(self):
200 with self.assertRaisesRegex(TypeError,
201 (r"^Pins and DiffPairs are incompatible with other location or subsignal "
202 r"constraints, but \(pins io A1\) appears after \(pins io A0\)$")):
203 s = Subsignal("a", Pins("A0"), Pins("A1"))
204
205 def test_wrong_diffpairs(self):
206 with self.assertRaisesRegex(TypeError,
207 (r"^Pins and DiffPairs are incompatible with other location or subsignal "
208 r"constraints, but \(pins io A1\) appears after \(diffpairs io \(p A0\) \(n B0\)\)$")):
209 s = Subsignal("a", DiffPairs("A0", "B0"), Pins("A1"))
210
211 def test_wrong_subsignals(self):
212 with self.assertRaisesRegex(TypeError,
213 (r"^Pins and DiffPairs are incompatible with other location or subsignal "
214 r"constraints, but \(pins io B0\) appears after \(subsignal b \(pins io A0\)\)$")):
215 s = Subsignal("a", Subsignal("b", Pins("A0")), Pins("B0"))
216
217 def test_wrong_clock(self):
218 with self.assertRaisesRegex(TypeError,
219 (r"^Clock constraint can only be applied to Pins or DiffPairs, not "
220 r"\(subsignal b \(pins io A0\)\)$")):
221 s = Subsignal("a", Subsignal("b", Pins("A0")), Clock(1e6))
222
223 def test_wrong_clock_many(self):
224 with self.assertRaisesRegex(ValueError,
225 r"^Clock constraint can be applied only once$"):
226 s = Subsignal("a", Pins("A0"), Clock(1e6), Clock(1e7))
227
228
229 class ResourceTestCase(FHDLTestCase):
230 def test_basic(self):
231 r = Resource("serial", 0,
232 Subsignal("tx", Pins("A0", dir="o")),
233 Subsignal("rx", Pins("A1", dir="i")),
234 Attrs(IOSTANDARD="LVCMOS33"))
235 self.assertEqual(repr(r), "(resource serial 0"
236 " (subsignal tx (pins o A0))"
237 " (subsignal rx (pins i A1))"
238 " (attrs IOSTANDARD='LVCMOS33'))")
239
240 def test_family(self):
241 ios = [Subsignal("clk", Pins("A0", dir="o"))]
242 r1 = Resource.family(0, default_name="spi", ios=ios)
243 r2 = Resource.family("spi_flash", 0, default_name="spi", ios=ios)
244 r3 = Resource.family("spi_flash", 0, default_name="spi", ios=ios, name_suffix="4x")
245 r4 = Resource.family(0, default_name="spi", ios=ios, name_suffix="2x")
246 self.assertEqual(r1.name, "spi")
247 self.assertEqual(r1.ios, ios)
248 self.assertEqual(r2.name, "spi_flash")
249 self.assertEqual(r2.ios, ios)
250 self.assertEqual(r3.name, "spi_flash_4x")
251 self.assertEqual(r3.ios, ios)
252 self.assertEqual(r4.name, "spi_2x")
253 self.assertEqual(r4.ios, ios)
254
255
256 class ConnectorTestCase(FHDLTestCase):
257 def test_string(self):
258 c = Connector("pmod", 0, "A0 A1 A2 A3 - - A4 A5 A6 A7 - -")
259 self.assertEqual(c.name, "pmod")
260 self.assertEqual(c.number, 0)
261 self.assertEqual(c.mapping, OrderedDict([
262 ("1", "A0"),
263 ("2", "A1"),
264 ("3", "A2"),
265 ("4", "A3"),
266 ("7", "A4"),
267 ("8", "A5"),
268 ("9", "A6"),
269 ("10", "A7"),
270 ]))
271 self.assertEqual(list(c), [
272 ("pmod_0:1", "A0"),
273 ("pmod_0:2", "A1"),
274 ("pmod_0:3", "A2"),
275 ("pmod_0:4", "A3"),
276 ("pmod_0:7", "A4"),
277 ("pmod_0:8", "A5"),
278 ("pmod_0:9", "A6"),
279 ("pmod_0:10", "A7"),
280 ])
281 self.assertEqual(repr(c),
282 "(connector pmod 0 1=>A0 2=>A1 3=>A2 4=>A3 7=>A4 8=>A5 9=>A6 10=>A7)")
283
284 def test_dict(self):
285 c = Connector("ext", 1, {"DP0": "A0", "DP1": "A1"})
286 self.assertEqual(c.name, "ext")
287 self.assertEqual(c.number, 1)
288 self.assertEqual(c.mapping, OrderedDict([
289 ("DP0", "A0"),
290 ("DP1", "A1"),
291 ]))
292
293 def test_conn(self):
294 c = Connector("pmod", 0, "0 1 2 3 - - 4 5 6 7 - -", conn=("expansion", 0))
295 self.assertEqual(c.mapping, OrderedDict([
296 ("1", "expansion_0:0"),
297 ("2", "expansion_0:1"),
298 ("3", "expansion_0:2"),
299 ("4", "expansion_0:3"),
300 ("7", "expansion_0:4"),
301 ("8", "expansion_0:5"),
302 ("9", "expansion_0:6"),
303 ("10", "expansion_0:7"),
304 ]))
305
306 def test_str_name(self):
307 c = Connector("ext", "A", "0 1 2")
308 self.assertEqual(c.name, "ext")
309 self.assertEqual(c.number, "A")
310
311 def test_conn_wrong_name(self):
312 with self.assertRaisesRegex(TypeError,
313 (r"^Connector must be None or a pair of string \(connector name\) and "
314 r"integer\/string \(connector number\), not \('foo', None\)$")):
315 Connector("ext", "A", "0 1 2", conn=("foo", None))
316
317 def test_wrong_io(self):
318 with self.assertRaisesRegex(TypeError,
319 r"^Connector I\/Os must be a dictionary or a string, not \[\]$"):
320 Connector("pmod", 0, [])
321
322 def test_wrong_dict_key_value(self):
323 with self.assertRaisesRegex(TypeError,
324 r"^Connector pin name must be a string, not 0$"):
325 Connector("pmod", 0, {0: "A"})
326 with self.assertRaisesRegex(TypeError,
327 r"^Platform pin name must be a string, not 0$"):
328 Connector("pmod", 0, {"A": 0})