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