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 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
)
96 self
.assertEqual(list(self
.cm
.iter_port_constraints()), [
97 ("i2c_0__scl__io", ["N10"], {}),
98 ("i2c_0__sda__io", ["N11"], {})
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)
107 ports
= list(self
.cm
.iter_ports())
108 self
.assertEqual(len(ports
), 2)
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
)
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)
122 self
.assertEqual(list(self
.cm
.iter_port_constraints()), [
123 ("clk100_0__p", ["H1"], {}),
124 ("clk100_0__n", ["H2"], {}),
127 def test_request_inverted(self
):
129 Resource("cs", 0, PinsN("X0")),
130 Resource("clk", 0, DiffPairsN("Y0", "Y1")),
132 self
.cm
.add_resources(new_resources
)
134 cs
= self
.cm
.request("cs")
135 clk
= self
.cm
.request("clk")
136 cs_io
, clk_p
, clk_n
= self
.cm
.iter_ports()
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)
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)
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
)
156 ports
= list(self
.cm
.iter_ports())
157 self
.assertEqual(len(ports
), 1)
158 self
.assertIs(ports
[0], clk50
.io
)
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
)
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
)
171 def test_request_via_connector(self
):
172 self
.cm
.add_resources([
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))),
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"], {}),
188 def test_request_via_nested_connector(self
):
190 Connector("pmod_extension", 0, "1 2 3 4 - -", conn
=("pmod", 0)),
192 self
.cm
.add_connectors(new_connectors
)
193 self
.cm
.add_resources([
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))),
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"], {}),
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
)
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
)
225 def test_wrong_resources(self
):
226 with self
.assertRaisesRegex(TypeError, r
"^Object 'wrong' is not a Resource$"):
227 self
.cm
.add_resources(['wrong'])
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"))])
235 def test_wrong_connectors(self
):
236 with self
.assertRaisesRegex(TypeError, r
"^Object 'wrong' is not a Connector$"):
237 self
.cm
.add_connectors(['wrong'])
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")])
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)
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
)
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)
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)
266 def test_wrong_request_duplicate_physical(self
):
267 self
.cm
.add_resources([
268 Resource("clk20", 0, Pins("H1", dir="i")),
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)
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 \"-\", "
280 user_led = self.cm.request("user_led
", 0, dir="wrong
")
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
"
287 user_led = self.cm.request("user_led
", 0, dir="i
")
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
")
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)
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\
)\
)\
) "
306 i2c = self.cm.request("i2c
", 0, xdr=2)
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)