build.run: implement SSH remote builds using Paramiko.
[nmigen.git] / nmigen / test / test_build_res.py
1 # nmigen: UnusedElaboratable=no
2
3 from .. import *
4 from ..hdl.rec import *
5 from ..lib.io import *
6 from ..build.dsl import *
7 from ..build.res import *
8 from .utils import *
9
10
11 class ResourceManagerTestCase(FHDLTestCase):
12 def setUp(self):
13 self.resources = [
14 Resource("clk100", 0, DiffPairs("H1", "H2", dir="i"), Clock(100e6)),
15 Resource("clk50", 0, Pins("K1"), Clock(50e6)),
16 Resource("user_led", 0, Pins("A0", dir="o")),
17 Resource("i2c", 0,
18 Subsignal("scl", Pins("N10", dir="o")),
19 Subsignal("sda", Pins("N11"))
20 )
21 ]
22 self.connectors = [
23 Connector("pmod", 0, "B0 B1 B2 B3 - -"),
24 ]
25 self.cm = ResourceManager(self.resources, self.connectors)
26
27 def test_basic(self):
28 self.cm = ResourceManager(self.resources, self.connectors)
29 self.assertEqual(self.cm.resources, {
30 ("clk100", 0): self.resources[0],
31 ("clk50", 0): self.resources[1],
32 ("user_led", 0): self.resources[2],
33 ("i2c", 0): self.resources[3]
34 })
35 self.assertEqual(self.cm.connectors, {
36 ("pmod", 0): self.connectors[0],
37 })
38
39 def test_add_resources(self):
40 new_resources = [
41 Resource("user_led", 1, Pins("A1", dir="o"))
42 ]
43 self.cm.add_resources(new_resources)
44 self.assertEqual(self.cm.resources, {
45 ("clk100", 0): self.resources[0],
46 ("clk50", 0): self.resources[1],
47 ("user_led", 0): self.resources[2],
48 ("i2c", 0): self.resources[3],
49 ("user_led", 1): new_resources[0]
50 })
51
52 def test_lookup(self):
53 r = self.cm.lookup("user_led", 0)
54 self.assertIs(r, self.cm.resources["user_led", 0])
55
56 def test_request_basic(self):
57 r = self.cm.lookup("user_led", 0)
58 user_led = self.cm.request("user_led", 0)
59
60 self.assertIsInstance(user_led, Pin)
61 self.assertEqual(user_led.name, "user_led_0")
62 self.assertEqual(user_led.width, 1)
63 self.assertEqual(user_led.dir, "o")
64
65 ports = list(self.cm.iter_ports())
66 self.assertEqual(len(ports), 1)
67
68 self.assertEqual(list(self.cm.iter_port_constraints()), [
69 ("user_led_0__io", ["A0"], {})
70 ])
71
72 def test_request_with_dir(self):
73 i2c = self.cm.request("i2c", 0, dir={"sda": "o"})
74 self.assertIsInstance(i2c, Record)
75 self.assertIsInstance(i2c.sda, Pin)
76 self.assertEqual(i2c.sda.dir, "o")
77
78 def test_request_tristate(self):
79 i2c = self.cm.request("i2c", 0)
80 self.assertEqual(i2c.sda.dir, "io")
81
82 ports = list(self.cm.iter_ports())
83 self.assertEqual(len(ports), 2)
84 scl, sda = ports
85 self.assertEqual(ports[1].name, "i2c_0__sda__io")
86 self.assertEqual(ports[1].width, 1)
87
88 scl_info, sda_info = self.cm.iter_single_ended_pins()
89 self.assertIs(scl_info[0], i2c.scl)
90 self.assertIs(scl_info[1].io, scl)
91 self.assertEqual(scl_info[2], {})
92 self.assertEqual(scl_info[3], False)
93 self.assertIs(sda_info[0], i2c.sda)
94 self.assertIs(sda_info[1].io, sda)
95
96 self.assertEqual(list(self.cm.iter_port_constraints()), [
97 ("i2c_0__scl__io", ["N10"], {}),
98 ("i2c_0__sda__io", ["N11"], {})
99 ])
100
101 def test_request_diffpairs(self):
102 clk100 = self.cm.request("clk100", 0)
103 self.assertIsInstance(clk100, Pin)
104 self.assertEqual(clk100.dir, "i")
105 self.assertEqual(clk100.width, 1)
106
107 ports = list(self.cm.iter_ports())
108 self.assertEqual(len(ports), 2)
109 p, n = ports
110 self.assertEqual(p.name, "clk100_0__p")
111 self.assertEqual(p.width, clk100.width)
112 self.assertEqual(n.name, "clk100_0__n")
113 self.assertEqual(n.width, clk100.width)
114
115 clk100_info, = self.cm.iter_differential_pins()
116 self.assertIs(clk100_info[0], clk100)
117 self.assertIs(clk100_info[1].p, p)
118 self.assertIs(clk100_info[1].n, n)
119 self.assertEqual(clk100_info[2], {})
120 self.assertEqual(clk100_info[3], False)
121
122 self.assertEqual(list(self.cm.iter_port_constraints()), [
123 ("clk100_0__p", ["H1"], {}),
124 ("clk100_0__n", ["H2"], {}),
125 ])
126
127 def test_request_inverted(self):
128 new_resources = [
129 Resource("cs", 0, PinsN("X0")),
130 Resource("clk", 0, DiffPairsN("Y0", "Y1")),
131 ]
132 self.cm.add_resources(new_resources)
133
134 cs = self.cm.request("cs")
135 clk = self.cm.request("clk")
136 cs_io, clk_p, clk_n = self.cm.iter_ports()
137
138 cs_info, = self.cm.iter_single_ended_pins()
139 self.assertIs(cs_info[0], cs)
140 self.assertIs(cs_info[1].io, cs_io)
141 self.assertEqual(cs_info[2], {})
142 self.assertEqual(cs_info[3], True)
143
144 clk_info, = self.cm.iter_differential_pins()
145 self.assertIs(clk_info[0], clk)
146 self.assertIs(clk_info[1].p, clk_p)
147 self.assertIs(clk_info[1].n, clk_n)
148 self.assertEqual(clk_info[2], {})
149 self.assertEqual(clk_info[3], True)
150
151 def test_request_raw(self):
152 clk50 = self.cm.request("clk50", 0, dir="-")
153 self.assertIsInstance(clk50, Record)
154 self.assertIsInstance(clk50.io, Signal)
155
156 ports = list(self.cm.iter_ports())
157 self.assertEqual(len(ports), 1)
158 self.assertIs(ports[0], clk50.io)
159
160 def test_request_raw_diffpairs(self):
161 clk100 = self.cm.request("clk100", 0, dir="-")
162 self.assertIsInstance(clk100, Record)
163 self.assertIsInstance(clk100.p, Signal)
164 self.assertIsInstance(clk100.n, Signal)
165
166 ports = list(self.cm.iter_ports())
167 self.assertEqual(len(ports), 2)
168 self.assertIs(ports[0], clk100.p)
169 self.assertIs(ports[1], clk100.n)
170
171 def test_request_via_connector(self):
172 self.cm.add_resources([
173 Resource("spi", 0,
174 Subsignal("ss", Pins("1", conn=("pmod", 0))),
175 Subsignal("clk", Pins("2", conn=("pmod", 0))),
176 Subsignal("miso", Pins("3", conn=("pmod", 0))),
177 Subsignal("mosi", Pins("4", conn=("pmod", 0))),
178 )
179 ])
180 spi0 = self.cm.request("spi", 0)
181 self.assertEqual(list(self.cm.iter_port_constraints()), [
182 ("spi_0__ss__io", ["B0"], {}),
183 ("spi_0__clk__io", ["B1"], {}),
184 ("spi_0__miso__io", ["B2"], {}),
185 ("spi_0__mosi__io", ["B3"], {}),
186 ])
187
188 def test_request_via_nested_connector(self):
189 new_connectors = [
190 Connector("pmod_extension", 0, "1 2 3 4 - -", conn=("pmod", 0)),
191 ]
192 self.cm.add_connectors(new_connectors)
193 self.cm.add_resources([
194 Resource("spi", 0,
195 Subsignal("ss", Pins("1", conn=("pmod_extension", 0))),
196 Subsignal("clk", Pins("2", conn=("pmod_extension", 0))),
197 Subsignal("miso", Pins("3", conn=("pmod_extension", 0))),
198 Subsignal("mosi", Pins("4", conn=("pmod_extension", 0))),
199 )
200 ])
201 spi0 = self.cm.request("spi", 0)
202 self.assertEqual(list(self.cm.iter_port_constraints()), [
203 ("spi_0__ss__io", ["B0"], {}),
204 ("spi_0__clk__io", ["B1"], {}),
205 ("spi_0__miso__io", ["B2"], {}),
206 ("spi_0__mosi__io", ["B3"], {}),
207 ])
208
209 def test_request_clock(self):
210 clk100 = self.cm.request("clk100", 0)
211 clk50 = self.cm.request("clk50", 0, dir="i")
212 clk100_port_p, clk100_port_n, clk50_port = self.cm.iter_ports()
213 self.assertEqual(list(self.cm.iter_clock_constraints()), [
214 (clk100.i, clk100_port_p, 100e6),
215 (clk50.i, clk50_port, 50e6)
216 ])
217
218 def test_add_clock(self):
219 i2c = self.cm.request("i2c")
220 self.cm.add_clock_constraint(i2c.scl.o, 100e3)
221 self.assertEqual(list(self.cm.iter_clock_constraints()), [
222 (i2c.scl.o, None, 100e3)
223 ])
224
225 def test_wrong_resources(self):
226 with self.assertRaisesRegex(TypeError, r"^Object 'wrong' is not a Resource$"):
227 self.cm.add_resources(['wrong'])
228
229 def test_wrong_resources_duplicate(self):
230 with self.assertRaisesRegex(NameError,
231 (r"^Trying to add \(resource user_led 0 \(pins o A1\)\), but "
232 r"\(resource user_led 0 \(pins o A0\)\) has the same name and number$")):
233 self.cm.add_resources([Resource("user_led", 0, Pins("A1", dir="o"))])
234
235 def test_wrong_connectors(self):
236 with self.assertRaisesRegex(TypeError, r"^Object 'wrong' is not a Connector$"):
237 self.cm.add_connectors(['wrong'])
238
239 def test_wrong_connectors_duplicate(self):
240 with self.assertRaisesRegex(NameError,
241 (r"^Trying to add \(connector pmod 0 1=>1 2=>2\), but "
242 r"\(connector pmod 0 1=>B0 2=>B1 3=>B2 4=>B3\) has the same name and number$")):
243 self.cm.add_connectors([Connector("pmod", 0, "1 2")])
244
245 def test_wrong_lookup(self):
246 with self.assertRaisesRegex(ResourceError,
247 r"^Resource user_led#1 does not exist$"):
248 r = self.cm.lookup("user_led", 1)
249
250 def test_wrong_clock_signal(self):
251 with self.assertRaisesRegex(TypeError,
252 r"^Object None is not a Signal$"):
253 self.cm.add_clock_constraint(None, 10e6)
254
255 def test_wrong_clock_frequency(self):
256 with self.assertRaisesRegex(TypeError,
257 r"^Frequency must be a number, not None$"):
258 self.cm.add_clock_constraint(Signal(), None)
259
260 def test_wrong_request_duplicate(self):
261 with self.assertRaisesRegex(ResourceError,
262 r"^Resource user_led#0 has already been requested$"):
263 self.cm.request("user_led", 0)
264 self.cm.request("user_led", 0)
265
266 def test_wrong_request_duplicate_physical(self):
267 self.cm.add_resources([
268 Resource("clk20", 0, Pins("H1", dir="i")),
269 ])
270 self.cm.request("clk100", 0)
271 with self.assertRaisesRegex(ResourceError,
272 (r"^Resource component clk20_0 uses physical pin H1, but it is already "
273 r"used by resource component clk100_0 that was requested earlier$")):
274 self.cm.request("clk20", 0)
275
276 def test_wrong_request_with_dir(self):
277 with self.assertRaisesRegex(TypeError,
278 (r"^Direction must be one of \"i\", \"o\", \"oe\", \"io\", or \"-\", "
279 r"not 'wrong'$")):
280 user_led = self.cm.request("user_led", 0, dir="wrong")
281
282 def test_wrong_request_with_dir_io(self):
283 with self.assertRaisesRegex(ValueError,
284 (r"^Direction of \(pins o A0\) cannot be changed from \"o\" to \"i\"; direction "
285 r"can be changed from \"io\" to \"i\", \"o\", or \"oe\", or from anything "
286 r"to \"-\"$")):
287 user_led = self.cm.request("user_led", 0, dir="i")
288
289 def test_wrong_request_with_dir_dict(self):
290 with self.assertRaisesRegex(TypeError,
291 (r"^Directions must be a dict, not 'i', because \(resource i2c 0 \(subsignal scl "
292 r"\(pins o N10\)\) \(subsignal sda \(pins io N11\)\)\) "
293 r"has subsignals$")):
294 i2c = self.cm.request("i2c", 0, dir="i")
295
296 def test_wrong_request_with_wrong_xdr(self):
297 with self.assertRaisesRegex(ValueError,
298 r"^Data rate of \(pins o A0\) must be a non-negative integer, not -1$"):
299 user_led = self.cm.request("user_led", 0, xdr=-1)
300
301 def test_wrong_request_with_xdr_dict(self):
302 with self.assertRaisesRegex(TypeError,
303 r"^Data rate must be a dict, not 2, because \(resource i2c 0 \(subsignal scl "
304 r"\(pins o N10\)\) \(subsignal sda \(pins io N11\)\)\) "
305 r"has subsignals$"):
306 i2c = self.cm.request("i2c", 0, xdr=2)
307
308 def test_wrong_clock_constraint_twice(self):
309 clk100 = self.cm.request("clk100")
310 with self.assertRaisesRegex(ValueError,
311 (r"^Cannot add clock constraint on \(sig clk100_0__i\), which is already "
312 r"constrained to 100000000\.0 Hz$")):
313 self.cm.add_clock_constraint(clk100.i, 1e6)