3b3a9d5e9af3b88b7534a74d7a0b121ef8d305dd
[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 self.assertEqual(list(self.cm.iter_single_ended_pins()), [
89 (i2c.scl, scl, {}, False),
90 (i2c.sda, sda, {}, False),
91 ])
92 self.assertEqual(list(self.cm.iter_port_constraints()), [
93 ("i2c_0__scl__io", ["N10"], {}),
94 ("i2c_0__sda__io", ["N11"], {})
95 ])
96
97 def test_request_diffpairs(self):
98 clk100 = self.cm.request("clk100", 0)
99 self.assertIsInstance(clk100, Pin)
100 self.assertEqual(clk100.dir, "i")
101 self.assertEqual(clk100.width, 1)
102
103 ports = list(self.cm.iter_ports())
104 self.assertEqual(len(ports), 2)
105 p, n = ports
106 self.assertEqual(p.name, "clk100_0__p")
107 self.assertEqual(p.width, clk100.width)
108 self.assertEqual(n.name, "clk100_0__n")
109 self.assertEqual(n.width, clk100.width)
110
111 self.assertEqual(list(self.cm.iter_differential_pins()), [
112 (clk100, p, n, {}, False),
113 ])
114 self.assertEqual(list(self.cm.iter_port_constraints()), [
115 ("clk100_0__p", ["H1"], {}),
116 ("clk100_0__n", ["H2"], {}),
117 ])
118
119 def test_request_inverted(self):
120 new_resources = [
121 Resource("cs", 0, PinsN("X0")),
122 Resource("clk", 0, DiffPairsN("Y0", "Y1")),
123 ]
124 self.cm.add_resources(new_resources)
125
126 sig_cs = self.cm.request("cs")
127 sig_clk = self.cm.request("clk")
128 port_cs, port_clk_p, port_clk_n = self.cm.iter_ports()
129 self.assertEqual(list(self.cm.iter_single_ended_pins()), [
130 (sig_cs, port_cs, {}, True),
131 ])
132 self.assertEqual(list(self.cm.iter_differential_pins()), [
133 (sig_clk, port_clk_p, port_clk_n, {}, True),
134 ])
135
136 def test_request_raw(self):
137 clk50 = self.cm.request("clk50", 0, dir="-")
138 self.assertIsInstance(clk50, Record)
139 self.assertIsInstance(clk50.io, Signal)
140
141 ports = list(self.cm.iter_ports())
142 self.assertEqual(len(ports), 1)
143 self.assertIs(ports[0], clk50.io)
144
145 def test_request_raw_diffpairs(self):
146 clk100 = self.cm.request("clk100", 0, dir="-")
147 self.assertIsInstance(clk100, Record)
148 self.assertIsInstance(clk100.p, Signal)
149 self.assertIsInstance(clk100.n, Signal)
150
151 ports = list(self.cm.iter_ports())
152 self.assertEqual(len(ports), 2)
153 self.assertIs(ports[0], clk100.p)
154 self.assertIs(ports[1], clk100.n)
155
156 def test_request_via_connector(self):
157 self.cm.add_resources([
158 Resource("spi", 0,
159 Subsignal("ss", Pins("1", conn=("pmod", 0))),
160 Subsignal("clk", Pins("2", conn=("pmod", 0))),
161 Subsignal("miso", Pins("3", conn=("pmod", 0))),
162 Subsignal("mosi", Pins("4", conn=("pmod", 0))),
163 )
164 ])
165 spi0 = self.cm.request("spi", 0)
166 self.assertEqual(list(self.cm.iter_port_constraints()), [
167 ("spi_0__ss__io", ["B0"], {}),
168 ("spi_0__clk__io", ["B1"], {}),
169 ("spi_0__miso__io", ["B2"], {}),
170 ("spi_0__mosi__io", ["B3"], {}),
171 ])
172
173 def test_request_via_nested_connector(self):
174 new_connectors = [
175 Connector("pmod_extension", 0, "1 2 3 4 - -", conn=("pmod", 0)),
176 ]
177 self.cm.add_connectors(new_connectors)
178 self.cm.add_resources([
179 Resource("spi", 0,
180 Subsignal("ss", Pins("1", conn=("pmod_extension", 0))),
181 Subsignal("clk", Pins("2", conn=("pmod_extension", 0))),
182 Subsignal("miso", Pins("3", conn=("pmod_extension", 0))),
183 Subsignal("mosi", Pins("4", conn=("pmod_extension", 0))),
184 )
185 ])
186 spi0 = self.cm.request("spi", 0)
187 self.assertEqual(list(self.cm.iter_port_constraints()), [
188 ("spi_0__ss__io", ["B0"], {}),
189 ("spi_0__clk__io", ["B1"], {}),
190 ("spi_0__miso__io", ["B2"], {}),
191 ("spi_0__mosi__io", ["B3"], {}),
192 ])
193
194 def test_request_clock(self):
195 clk100 = self.cm.request("clk100", 0)
196 clk50 = self.cm.request("clk50", 0, dir="i")
197 clk100_port_p, clk100_port_n, clk50_port = self.cm.iter_ports()
198 self.assertEqual(list(self.cm.iter_clock_constraints()), [
199 (clk100.i, clk100_port_p, 100e6),
200 (clk50.i, clk50_port, 50e6)
201 ])
202
203 def test_add_clock(self):
204 i2c = self.cm.request("i2c")
205 self.cm.add_clock_constraint(i2c.scl.o, 100e3)
206 self.assertEqual(list(self.cm.iter_clock_constraints()), [
207 (i2c.scl.o, None, 100e3)
208 ])
209
210 def test_wrong_resources(self):
211 with self.assertRaises(TypeError, msg="Object 'wrong' is not a Resource"):
212 self.cm.add_resources(['wrong'])
213
214 def test_wrong_resources_duplicate(self):
215 with self.assertRaises(NameError,
216 msg="Trying to add (resource user_led 0 (pins o A1)), but "
217 "(resource user_led 0 (pins o A0)) has the same name and number"):
218 self.cm.add_resources([Resource("user_led", 0, Pins("A1", dir="o"))])
219
220 def test_wrong_connectors(self):
221 with self.assertRaises(TypeError, msg="Object 'wrong' is not a Connector"):
222 self.cm.add_connectors(['wrong'])
223
224 def test_wrong_connectors_duplicate(self):
225 with self.assertRaises(NameError,
226 msg="Trying to add (connector pmod 0 1=>1 2=>2), but "
227 "(connector pmod 0 1=>B0 2=>B1 3=>B2 4=>B3) has the same name and number"):
228 self.cm.add_connectors([Connector("pmod", 0, "1 2")])
229
230 def test_wrong_lookup(self):
231 with self.assertRaises(ResourceError,
232 msg="Resource user_led#1 does not exist"):
233 r = self.cm.lookup("user_led", 1)
234
235 def test_wrong_clock_signal(self):
236 with self.assertRaises(TypeError,
237 msg="Object None is not a Signal"):
238 self.cm.add_clock_constraint(None, 10e6)
239
240 def test_wrong_clock_frequency(self):
241 with self.assertRaises(TypeError,
242 msg="Frequency must be a number, not None"):
243 self.cm.add_clock_constraint(Signal(), None)
244
245 def test_wrong_request_duplicate(self):
246 with self.assertRaises(ResourceError,
247 msg="Resource user_led#0 has already been requested"):
248 self.cm.request("user_led", 0)
249 self.cm.request("user_led", 0)
250
251 def test_wrong_request_duplicate_physical(self):
252 self.cm.add_resources([
253 Resource("clk20", 0, Pins("H1", dir="i")),
254 ])
255 self.cm.request("clk100", 0)
256 with self.assertRaises(ResourceError,
257 msg="Resource component clk20_0 uses physical pin H1, but it is already "
258 "used by resource component clk100_0 that was requested earlier"):
259 self.cm.request("clk20", 0)
260
261 def test_wrong_request_with_dir(self):
262 with self.assertRaises(TypeError,
263 msg="Direction must be one of \"i\", \"o\", \"oe\", \"io\", or \"-\", "
264 "not 'wrong'"):
265 user_led = self.cm.request("user_led", 0, dir="wrong")
266
267 def test_wrong_request_with_dir_io(self):
268 with self.assertRaises(ValueError,
269 msg="Direction of (pins o A0) cannot be changed from \"o\" to \"i\"; direction "
270 "can be changed from \"io\" to \"i\", \"o\", or \"oe\", or from anything "
271 "to \"-\""):
272 user_led = self.cm.request("user_led", 0, dir="i")
273
274 def test_wrong_request_with_dir_dict(self):
275 with self.assertRaises(TypeError,
276 msg="Directions must be a dict, not 'i', because (resource i2c 0 (subsignal scl "
277 "(pins o N10)) (subsignal sda (pins io N11))) "
278 "has subsignals"):
279 i2c = self.cm.request("i2c", 0, dir="i")
280
281 def test_wrong_request_with_wrong_xdr(self):
282 with self.assertRaises(ValueError,
283 msg="Data rate of (pins o A0) must be a non-negative integer, not -1"):
284 user_led = self.cm.request("user_led", 0, xdr=-1)
285
286 def test_wrong_request_with_xdr_dict(self):
287 with self.assertRaises(TypeError,
288 msg="Data rate must be a dict, not 2, because (resource i2c 0 (subsignal scl "
289 "(pins o N10)) (subsignal sda (pins io N11))) "
290 "has subsignals"):
291 i2c = self.cm.request("i2c", 0, xdr=2)
292
293 def test_wrong_clock_constraint_twice(self):
294 clk100 = self.cm.request("clk100")
295 with self.assertRaises(ValueError,
296 msg="Cannot add clock constraint on (sig clk100_0__i), which is already "
297 "constrained to 100000000.0 Hz"):
298 self.cm.add_clock_constraint(clk100.i, 1e6)