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
.assertRaisesRegex(TypeError, r
"^Object 'wrong' is not a Resource$"):
212 self
.cm
.add_resources(['wrong'])
214 def test_wrong_resources_duplicate(self
):
215 with self
.assertRaisesRegex(NameError,
216 (r
"^Trying to add \(resource user_led 0 \(pins o A1\)\), but "
217 r
"\(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
.assertRaisesRegex(TypeError, r
"^Object 'wrong' is not a Connector$"):
222 self
.cm
.add_connectors(['wrong'])
224 def test_wrong_connectors_duplicate(self
):
225 with self
.assertRaisesRegex(NameError,
226 (r
"^Trying to add \(connector pmod 0 1=>1 2=>2\), but "
227 r
"\(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
.assertRaisesRegex(ResourceError
,
232 r
"^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
.assertRaisesRegex(TypeError,
237 r
"^Object None is not a Signal$"):
238 self
.cm
.add_clock_constraint(None, 10e6
)
240 def test_wrong_clock_frequency(self
):
241 with self
.assertRaisesRegex(TypeError,
242 r
"^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
.assertRaisesRegex(ResourceError
,
247 r
"^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
.assertRaisesRegex(ResourceError
,
257 (r
"^Resource component clk20_0 uses physical pin H1, but it is already "
258 r
"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
.assertRaisesRegex(TypeError,
263 (r
"^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.assertRaisesRegex(ValueError,
269 (r"^Direction of \
(pins o A0\
) cannot be changed
from \"o
\" to
\"i
\"; direction
"
270 r"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.assertRaisesRegex(TypeError,
276 (r"^Directions must be a
dict, not 'i', because \
(resource i2c
0 \
(subsignal scl
"
277 r"\
(pins o N10\
)\
) \
(subsignal sda \
(pins io N11\
)\
)\
) "
278 r"has subsignals$
")):
279 i2c = self.cm.request("i2c
", 0, dir="i
")
281 def test_wrong_request_with_wrong_xdr(self):
282 with self.assertRaisesRegex(ValueError,
283 r"^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.assertRaisesRegex(TypeError,
288 r"^Data rate must be a
dict, not 2, because \
(resource i2c
0 \
(subsignal scl
"
289 r"\
(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.assertRaisesRegex(ValueError,
296 (r"^Cannot add clock constraint on \
(sig clk100_0__i\
), which
is already
"
297 r"constrained to
100000000\
.0 Hz$
")):
298 self.cm.add_clock_constraint(clk100.i, 1e6)