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