3b3a9d5e9af3b88b7534a74d7a0b121ef8d305dd
1 # nmigen: UnusedElaboratable=no
4 from ..hdl
.rec
import *
6 from ..build
.dsl
import *
7 from ..build
.res
import *
11 class ResourceManagerTestCase(FHDLTestCase
):
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")),
18 Subsignal("scl", Pins("N10", dir="o")),
19 Subsignal("sda", Pins("N11"))
23 Connector("pmod", 0, "B0 B1 B2 B3 - -"),
25 self
.cm
= ResourceManager(self
.resources
, self
.connectors
)
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]
35 self
.assertEqual(self
.cm
.connectors
, {
36 ("pmod", 0): self
.connectors
[0],
39 def test_add_resources(self
):
41 Resource("user_led", 1, Pins("A1", dir="o"))
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]
52 def test_lookup(self
):
53 r
= self
.cm
.lookup("user_led", 0)
54 self
.assertIs(r
, self
.cm
.resources
["user_led", 0])
56 def test_request_basic(self
):
57 r
= self
.cm
.lookup("user_led", 0)
58 user_led
= self
.cm
.request("user_led", 0)
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")
65 ports
= list(self
.cm
.iter_ports())
66 self
.assertEqual(len(ports
), 1)
68 self
.assertEqual(list(self
.cm
.iter_port_constraints()), [
69 ("user_led_0__io", ["A0"], {})
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")
78 def test_request_tristate(self
):
79 i2c
= self
.cm
.request("i2c", 0)
80 self
.assertEqual(i2c
.sda
.dir, "io")
82 ports
= list(self
.cm
.iter_ports())
83 self
.assertEqual(len(ports
), 2)
85 self
.assertEqual(ports
[1].name
, "i2c_0__sda__io")
86 self
.assertEqual(ports
[1].width
, 1)
88 self
.assertEqual(list(self
.cm
.iter_single_ended_pins()), [
89 (i2c
.scl
, scl
, {}, False),
90 (i2c
.sda
, sda
, {}, False),
92 self
.assertEqual(list(self
.cm
.iter_port_constraints()), [
93 ("i2c_0__scl__io", ["N10"], {}),
94 ("i2c_0__sda__io", ["N11"], {})
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)
103 ports
= list(self
.cm
.iter_ports())
104 self
.assertEqual(len(ports
), 2)
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
)
111 self
.assertEqual(list(self
.cm
.iter_differential_pins()), [
112 (clk100
, p
, n
, {}, False),
114 self
.assertEqual(list(self
.cm
.iter_port_constraints()), [
115 ("clk100_0__p", ["H1"], {}),
116 ("clk100_0__n", ["H2"], {}),
119 def test_request_inverted(self
):
121 Resource("cs", 0, PinsN("X0")),
122 Resource("clk", 0, DiffPairsN("Y0", "Y1")),
124 self
.cm
.add_resources(new_resources
)
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),
132 self
.assertEqual(list(self
.cm
.iter_differential_pins()), [
133 (sig_clk
, port_clk_p
, port_clk_n
, {}, True),
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
)
141 ports
= list(self
.cm
.iter_ports())
142 self
.assertEqual(len(ports
), 1)
143 self
.assertIs(ports
[0], clk50
.io
)
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
)
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
)
156 def test_request_via_connector(self
):
157 self
.cm
.add_resources([
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))),
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"], {}),
173 def test_request_via_nested_connector(self
):
175 Connector("pmod_extension", 0, "1 2 3 4 - -", conn
=("pmod", 0)),
177 self
.cm
.add_connectors(new_connectors
)
178 self
.cm
.add_resources([
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))),
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"], {}),
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
)
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
)
210 def test_wrong_resources(self
):
211 with self
.assertRaises(TypeError, msg
="Object 'wrong' is not a Resource"):
212 self
.cm
.add_resources(['wrong'])
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"))])
220 def test_wrong_connectors(self
):
221 with self
.assertRaises(TypeError, msg
="Object 'wrong' is not a Connector"):
222 self
.cm
.add_connectors(['wrong'])
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")])
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)
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
)
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)
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)
251 def test_wrong_request_duplicate_physical(self
):
252 self
.cm
.add_resources([
253 Resource("clk20", 0, Pins("H1", dir="i")),
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)
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 \"-\", "
265 user_led
= self
.cm
.request("user_led", 0, dir="wrong")
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 "
272 user_led
= self
.cm
.request("user_led", 0, dir="i")
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))) "
279 i2c
= self
.cm
.request("i2c", 0, dir="i")
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)
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))) "
291 i2c
= self
.cm
.request("i2c", 0, xdr
=2)
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
)