2021-12-09 22:39:50 -07:00
|
|
|
# amaranth: UnusedElaboratable=no
|
2019-10-26 00:36:54 -06:00
|
|
|
|
2024-03-14 23:37:17 -06:00
|
|
|
from amaranth.hdl import *
|
2023-08-31 21:27:31 -06:00
|
|
|
from amaranth.lib.wiring import *
|
2021-12-09 22:39:50 -07:00
|
|
|
from amaranth.lib.io import *
|
|
|
|
from amaranth.build.dsl import *
|
|
|
|
from amaranth.build.res import *
|
2024-04-10 23:45:53 -06:00
|
|
|
from amaranth._utils import _ignore_deprecated
|
tests: move out of the main package.
Compared to tests in the repository root, tests in the package have
many downsides:
* Unless explicitly excluded in find_packages(), tests and their
support code effectively become a part of public API.
This, unfortunately, happened with FHDLTestCase, which was never
intended for downstream use.
* Even if explicitly excluded from the setuptools package, using
an editable install, or setting PYTHONPATH still allows accessing
the tests.
* Having a sub-package that is present in the source tree but not
exported (or, worse, exported only sometimes) is confusing.
* The name `nmigen.test` cannot be used for anything else, such as
testing utilities that *are* intended for downstream use.
2020-08-26 18:33:31 -06:00
|
|
|
|
2019-10-13 12:53:38 -06:00
|
|
|
from .utils import *
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
|
2019-06-05 01:02:08 -06:00
|
|
|
class ResourceManagerTestCase(FHDLTestCase):
|
2019-04-26 06:37:08 -06:00
|
|
|
def setUp(self):
|
|
|
|
self.resources = [
|
2019-06-05 02:48:36 -06:00
|
|
|
Resource("clk100", 0, DiffPairs("H1", "H2", dir="i"), Clock(100e6)),
|
|
|
|
Resource("clk50", 0, Pins("K1"), Clock(50e6)),
|
2019-04-26 06:37:08 -06:00
|
|
|
Resource("user_led", 0, Pins("A0", dir="o")),
|
|
|
|
Resource("i2c", 0,
|
|
|
|
Subsignal("scl", Pins("N10", dir="o")),
|
|
|
|
Subsignal("sda", Pins("N11"))
|
|
|
|
)
|
|
|
|
]
|
2019-06-03 09:02:15 -06:00
|
|
|
self.connectors = [
|
|
|
|
Connector("pmod", 0, "B0 B1 B2 B3 - -"),
|
|
|
|
]
|
2019-06-05 02:48:36 -06:00
|
|
|
self.cm = ResourceManager(self.resources, self.connectors)
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_basic(self):
|
2019-06-05 02:48:36 -06:00
|
|
|
self.cm = ResourceManager(self.resources, self.connectors)
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(self.cm.resources, {
|
|
|
|
("clk100", 0): self.resources[0],
|
|
|
|
("clk50", 0): self.resources[1],
|
|
|
|
("user_led", 0): self.resources[2],
|
|
|
|
("i2c", 0): self.resources[3]
|
|
|
|
})
|
2019-06-03 09:02:15 -06:00
|
|
|
self.assertEqual(self.cm.connectors, {
|
|
|
|
("pmod", 0): self.connectors[0],
|
|
|
|
})
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_add_resources(self):
|
|
|
|
new_resources = [
|
|
|
|
Resource("user_led", 1, Pins("A1", dir="o"))
|
|
|
|
]
|
|
|
|
self.cm.add_resources(new_resources)
|
|
|
|
self.assertEqual(self.cm.resources, {
|
|
|
|
("clk100", 0): self.resources[0],
|
|
|
|
("clk50", 0): self.resources[1],
|
|
|
|
("user_led", 0): self.resources[2],
|
|
|
|
("i2c", 0): self.resources[3],
|
|
|
|
("user_led", 1): new_resources[0]
|
|
|
|
})
|
|
|
|
|
|
|
|
def test_lookup(self):
|
|
|
|
r = self.cm.lookup("user_led", 0)
|
|
|
|
self.assertIs(r, self.cm.resources["user_led", 0])
|
|
|
|
|
|
|
|
def test_request_basic(self):
|
|
|
|
r = self.cm.lookup("user_led", 0)
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
user_led = self.cm.request("user_led", 0)
|
2019-04-26 06:37:08 -06:00
|
|
|
|
2023-08-31 21:27:31 -06:00
|
|
|
self.assertIsInstance(flipped(user_led), Pin)
|
2024-02-27 02:42:57 -07:00
|
|
|
self.assertEqual(user_led.o.name, "user_led_0__o")
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(user_led.width, 1)
|
|
|
|
self.assertEqual(user_led.dir, "o")
|
|
|
|
|
2024-04-13 02:32:46 -06:00
|
|
|
(pin, port, buffer), = self.cm.iter_pins()
|
|
|
|
buffer._MustUse__silence = True
|
2019-04-26 06:37:08 -06:00
|
|
|
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIs(pin, user_led)
|
|
|
|
self.assertEqual(port.io.name, "user_led_0__io")
|
|
|
|
self.assertEqual(port.io.metadata[0].name, "A0")
|
|
|
|
self.assertEqual(port.io.metadata[0].attrs, {})
|
|
|
|
self.assertEqual(port.direction, Direction.Output)
|
|
|
|
self.assertEqual(port.invert, (False,))
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_request_with_dir(self):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
i2c = self.cm.request("i2c", 0, dir={"sda": "o"})
|
2024-02-27 02:42:57 -07:00
|
|
|
self.assertIsInstance(flipped(i2c.sda), Pin)
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(i2c.sda.dir, "o")
|
2024-04-13 02:32:46 -06:00
|
|
|
((_, _, scl_buffer), (_, _, sda_buffer)) = self.cm.iter_pins()
|
|
|
|
scl_buffer._MustUse__silence = True
|
|
|
|
sda_buffer._MustUse__silence = True
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_request_tristate(self):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
i2c = self.cm.request("i2c", 0)
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(i2c.sda.dir, "io")
|
|
|
|
|
2024-04-13 02:32:46 -06:00
|
|
|
((scl_pin, scl_port, scl_buffer), (sda_pin, sda_port, sda_buffer)) = self.cm.iter_pins()
|
|
|
|
scl_buffer._MustUse__silence = True
|
|
|
|
sda_buffer._MustUse__silence = True
|
|
|
|
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIs(scl_pin, i2c.scl)
|
|
|
|
self.assertIs(sda_pin, i2c.sda)
|
|
|
|
self.assertEqual(scl_port.io.name, "i2c_0__scl__io")
|
|
|
|
self.assertEqual(scl_port.io.metadata[0].name, "N10")
|
|
|
|
self.assertEqual(sda_port.io.name, "i2c_0__sda__io")
|
|
|
|
self.assertEqual(sda_port.io.metadata[0].name, "N11")
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_request_diffpairs(self):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
clk100 = self.cm.request("clk100", 0)
|
2023-08-31 21:27:31 -06:00
|
|
|
self.assertIsInstance(flipped(clk100), Pin)
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(clk100.dir, "i")
|
|
|
|
self.assertEqual(clk100.width, 1)
|
|
|
|
|
2024-04-13 02:32:46 -06:00
|
|
|
(clk100_pin, clk100_port, buffer), = self.cm.iter_pins()
|
|
|
|
buffer._MustUse__silence = True
|
|
|
|
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIs(clk100_pin, clk100)
|
|
|
|
self.assertEqual(clk100_port.p.name, "clk100_0__p")
|
|
|
|
self.assertEqual(clk100_port.p.width, clk100.width)
|
|
|
|
self.assertEqual(clk100_port.n.name, "clk100_0__n")
|
|
|
|
self.assertEqual(clk100_port.n.width, clk100.width)
|
|
|
|
self.assertEqual(clk100_port.p.metadata[0].name, "H1")
|
|
|
|
self.assertEqual(clk100_port.n.metadata[0].name, "H2")
|
2019-04-26 06:37:08 -06:00
|
|
|
|
2019-06-12 08:42:39 -06:00
|
|
|
def test_request_inverted(self):
|
|
|
|
new_resources = [
|
|
|
|
Resource("cs", 0, PinsN("X0")),
|
|
|
|
Resource("clk", 0, DiffPairsN("Y0", "Y1")),
|
|
|
|
]
|
|
|
|
self.cm.add_resources(new_resources)
|
|
|
|
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
cs = self.cm.request("cs")
|
|
|
|
clk = self.cm.request("clk")
|
|
|
|
|
2024-04-10 16:32:13 -06:00
|
|
|
(
|
2024-04-13 02:32:46 -06:00
|
|
|
(cs_pin, cs_port, cs_buffer),
|
|
|
|
(clk_pin, clk_port, clk_buffer),
|
2024-04-10 16:32:13 -06:00
|
|
|
) = self.cm.iter_pins()
|
2024-04-13 02:32:46 -06:00
|
|
|
cs_buffer._MustUse__silence = True
|
|
|
|
clk_buffer._MustUse__silence = True
|
2020-07-31 07:17:39 -06:00
|
|
|
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIs(cs_pin, cs)
|
|
|
|
self.assertEqual(cs_port.invert, (True,))
|
|
|
|
self.assertIs(clk_pin, clk)
|
|
|
|
self.assertEqual(clk_port.invert, (True,))
|
2019-06-12 08:42:39 -06:00
|
|
|
|
2019-06-02 21:17:20 -06:00
|
|
|
def test_request_raw(self):
|
|
|
|
clk50 = self.cm.request("clk50", 0, dir="-")
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIsInstance(clk50, SingleEndedPort)
|
2024-03-14 23:37:17 -06:00
|
|
|
self.assertIsInstance(clk50.io, IOPort)
|
2019-06-02 21:17:20 -06:00
|
|
|
|
|
|
|
def test_request_raw_diffpairs(self):
|
|
|
|
clk100 = self.cm.request("clk100", 0, dir="-")
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIsInstance(clk100, DifferentialPort)
|
2024-03-14 23:37:17 -06:00
|
|
|
self.assertIsInstance(clk100.p, IOPort)
|
|
|
|
self.assertIsInstance(clk100.n, IOPort)
|
2019-06-02 21:17:20 -06:00
|
|
|
|
2019-06-03 09:02:15 -06:00
|
|
|
def test_request_via_connector(self):
|
|
|
|
self.cm.add_resources([
|
|
|
|
Resource("spi", 0,
|
2024-04-13 02:32:46 -06:00
|
|
|
Subsignal("cs", Pins("1", conn=("pmod", 0))),
|
2019-06-03 09:02:15 -06:00
|
|
|
Subsignal("clk", Pins("2", conn=("pmod", 0))),
|
2024-04-13 02:32:46 -06:00
|
|
|
Subsignal("cipo", Pins("3", conn=("pmod", 0))),
|
|
|
|
Subsignal("copi", Pins("4", conn=("pmod", 0))),
|
2019-06-03 09:02:15 -06:00
|
|
|
)
|
|
|
|
])
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
spi0 = self.cm.request("spi", 0)
|
2024-04-10 16:32:13 -06:00
|
|
|
(
|
2024-04-13 02:32:46 -06:00
|
|
|
(cs_pin, cs_port, cs_buffer),
|
|
|
|
(clk_pin, clk_port, clk_buffer),
|
|
|
|
(cipo_pin, cipo_port, cipo_buffer),
|
|
|
|
(copi_pin, copi_port, copi_buffer),
|
2024-04-10 16:32:13 -06:00
|
|
|
) = self.cm.iter_pins()
|
2024-04-13 02:32:46 -06:00
|
|
|
cs_buffer._MustUse__silence = True
|
|
|
|
clk_buffer._MustUse__silence = True
|
|
|
|
cipo_buffer._MustUse__silence = True
|
|
|
|
copi_buffer._MustUse__silence = True
|
|
|
|
self.assertIs(cs_pin, spi0.cs)
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIs(clk_pin, spi0.clk)
|
2024-04-13 02:32:46 -06:00
|
|
|
self.assertIs(cipo_pin, spi0.cipo)
|
|
|
|
self.assertIs(copi_pin, spi0.copi)
|
|
|
|
self.assertEqual(cs_port.io.metadata[0].name, "B0")
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertEqual(clk_port.io.metadata[0].name, "B1")
|
2024-04-13 02:32:46 -06:00
|
|
|
self.assertEqual(cipo_port.io.metadata[0].name, "B2")
|
|
|
|
self.assertEqual(copi_port.io.metadata[0].name, "B3")
|
2019-06-03 09:02:15 -06:00
|
|
|
|
2019-08-18 13:56:25 -06:00
|
|
|
def test_request_via_nested_connector(self):
|
|
|
|
new_connectors = [
|
|
|
|
Connector("pmod_extension", 0, "1 2 3 4 - -", conn=("pmod", 0)),
|
|
|
|
]
|
|
|
|
self.cm.add_connectors(new_connectors)
|
|
|
|
self.cm.add_resources([
|
|
|
|
Resource("spi", 0,
|
2024-04-13 02:32:46 -06:00
|
|
|
Subsignal("cs", Pins("1", conn=("pmod_extension", 0))),
|
2019-08-18 13:56:25 -06:00
|
|
|
Subsignal("clk", Pins("2", conn=("pmod_extension", 0))),
|
2024-04-13 02:32:46 -06:00
|
|
|
Subsignal("cipo", Pins("3", conn=("pmod_extension", 0))),
|
|
|
|
Subsignal("copi", Pins("4", conn=("pmod_extension", 0))),
|
2019-08-18 13:56:25 -06:00
|
|
|
)
|
|
|
|
])
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
spi0 = self.cm.request("spi", 0)
|
2024-04-10 16:32:13 -06:00
|
|
|
(
|
2024-04-13 02:32:46 -06:00
|
|
|
(cs_pin, cs_port, cs_buffer),
|
|
|
|
(clk_pin, clk_port, clk_buffer),
|
|
|
|
(cipo_pin, cipo_port, cipo_buffer),
|
|
|
|
(copi_pin, copi_port, copi_buffer),
|
2024-04-10 16:32:13 -06:00
|
|
|
) = self.cm.iter_pins()
|
2024-04-13 02:32:46 -06:00
|
|
|
cs_buffer._MustUse__silence = True
|
|
|
|
clk_buffer._MustUse__silence = True
|
|
|
|
cipo_buffer._MustUse__silence = True
|
|
|
|
copi_buffer._MustUse__silence = True
|
|
|
|
self.assertIs(cs_pin, spi0.cs)
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertIs(clk_pin, spi0.clk)
|
2024-04-13 02:32:46 -06:00
|
|
|
self.assertIs(cipo_pin, spi0.cipo)
|
|
|
|
self.assertIs(copi_pin, spi0.copi)
|
|
|
|
self.assertEqual(cs_port.io.metadata[0].name, "B0")
|
2024-04-10 16:32:13 -06:00
|
|
|
self.assertEqual(clk_port.io.metadata[0].name, "B1")
|
2024-04-13 02:32:46 -06:00
|
|
|
self.assertEqual(cipo_port.io.metadata[0].name, "B2")
|
|
|
|
self.assertEqual(copi_port.io.metadata[0].name, "B3")
|
2019-08-18 13:56:25 -06:00
|
|
|
|
2019-06-05 02:48:36 -06:00
|
|
|
def test_request_clock(self):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
clk100 = self.cm.request("clk100", 0)
|
|
|
|
clk50 = self.cm.request("clk50", 0, dir="i")
|
2024-04-10 16:32:13 -06:00
|
|
|
(
|
2024-04-13 02:32:46 -06:00
|
|
|
(clk100_pin, clk100_port, clk100_buffer),
|
|
|
|
(clk50_pin, clk50_port, clk50_buffer),
|
2024-04-10 16:32:13 -06:00
|
|
|
) = self.cm.iter_pins()
|
2024-04-13 02:32:46 -06:00
|
|
|
clk100_buffer._MustUse__silence = True
|
|
|
|
clk50_buffer._MustUse__silence = True
|
2019-06-05 02:48:36 -06:00
|
|
|
self.assertEqual(list(self.cm.iter_clock_constraints()), [
|
2024-04-10 16:32:13 -06:00
|
|
|
(clk100.i, clk100_port.p, 100e6),
|
|
|
|
(clk50.i, clk50_port.io, 50e6)
|
2019-06-05 02:48:36 -06:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_add_clock(self):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
i2c = self.cm.request("i2c")
|
build.res: simplify clock constraints.
Before this commit, it was possible to set and get clock constraints
placed on Pin objects. This was not a very good implementation, since
it relied on matching the identity of the provided Pin object to
a previously requested one. The only reason it worked like that is
deficiencies in nextpnr.
Since then, nextpnr has been fixed to allow setting constraints on
arbitrary nets. Correspondingly, backends that are using Synplify
were changed to use [get_nets] instead of [get_ports] in SDC files.
However, in some situations, Synplify does not allow specifying
ports in [get_nets]. (In fact, nextpnr had a similar problem, but
it has also been fixed.)
The simplest way to address this is to refer to the interior net
(after the input buffer), which always works. The only downside
of this is that requesting a clock as a raw pin using
platform.request("clk", dir="-")
and directly applying a constraint to it could fail in some cases.
This is not a significant issue.
2019-09-21 08:12:29 -06:00
|
|
|
self.cm.add_clock_constraint(i2c.scl.o, 100e3)
|
2019-06-05 02:48:36 -06:00
|
|
|
self.assertEqual(list(self.cm.iter_clock_constraints()), [
|
2020-02-06 17:07:19 -07:00
|
|
|
(i2c.scl.o, None, 100e3)
|
2019-04-26 06:37:08 -06:00
|
|
|
])
|
2024-04-13 02:32:46 -06:00
|
|
|
((_, _, scl_buffer), (_, _, sda_buffer)) = self.cm.iter_pins()
|
|
|
|
scl_buffer._MustUse__silence = True
|
|
|
|
sda_buffer._MustUse__silence = True
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_wrong_resources(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError, r"^Object 'wrong' is not a Resource$"):
|
2019-04-26 06:37:08 -06:00
|
|
|
self.cm.add_resources(['wrong'])
|
|
|
|
|
|
|
|
def test_wrong_resources_duplicate(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(NameError,
|
|
|
|
(r"^Trying to add \(resource user_led 0 \(pins o A1\)\), but "
|
|
|
|
r"\(resource user_led 0 \(pins o A0\)\) has the same name and number$")):
|
2019-04-26 06:37:08 -06:00
|
|
|
self.cm.add_resources([Resource("user_led", 0, Pins("A1", dir="o"))])
|
|
|
|
|
2019-06-03 09:02:15 -06:00
|
|
|
def test_wrong_connectors(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError, r"^Object 'wrong' is not a Connector$"):
|
2019-06-03 09:02:15 -06:00
|
|
|
self.cm.add_connectors(['wrong'])
|
|
|
|
|
|
|
|
def test_wrong_connectors_duplicate(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(NameError,
|
|
|
|
(r"^Trying to add \(connector pmod 0 1=>1 2=>2\), but "
|
|
|
|
r"\(connector pmod 0 1=>B0 2=>B1 3=>B2 4=>B3\) has the same name and number$")):
|
2019-06-03 09:02:15 -06:00
|
|
|
self.cm.add_connectors([Connector("pmod", 0, "1 2")])
|
|
|
|
|
2019-04-26 06:37:08 -06:00
|
|
|
def test_wrong_lookup(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(ResourceError,
|
|
|
|
r"^Resource user_led#1 does not exist$"):
|
2019-04-26 06:37:08 -06:00
|
|
|
r = self.cm.lookup("user_led", 1)
|
|
|
|
|
2019-06-05 02:48:36 -06:00
|
|
|
def test_wrong_clock_signal(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Object None is not a Signal$"):
|
2019-06-05 02:48:36 -06:00
|
|
|
self.cm.add_clock_constraint(None, 10e6)
|
2019-04-26 06:37:08 -06:00
|
|
|
|
2019-06-05 02:48:36 -06:00
|
|
|
def test_wrong_clock_frequency(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Frequency must be a number, not None$"):
|
2019-06-05 02:48:36 -06:00
|
|
|
self.cm.add_clock_constraint(Signal(), None)
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_wrong_request_duplicate(self):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
self.cm.request("user_led", 0)
|
2024-04-13 02:32:46 -06:00
|
|
|
(pin, port, buffer), = self.cm.iter_pins()
|
|
|
|
buffer._MustUse__silence = True
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(ResourceError,
|
|
|
|
r"^Resource user_led#0 has already been requested$"):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
self.cm.request("user_led", 0)
|
2019-04-26 06:37:08 -06:00
|
|
|
|
2019-07-03 09:07:44 -06:00
|
|
|
def test_wrong_request_duplicate_physical(self):
|
|
|
|
self.cm.add_resources([
|
|
|
|
Resource("clk20", 0, Pins("H1", dir="i")),
|
|
|
|
])
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
self.cm.request("clk100", 0)
|
2024-04-13 02:32:46 -06:00
|
|
|
(pin, port, buffer), = self.cm.iter_pins()
|
|
|
|
buffer._MustUse__silence = True
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(ResourceError,
|
|
|
|
(r"^Resource component clk20_0 uses physical pin H1, but it is already "
|
|
|
|
r"used by resource component clk100_0 that was requested earlier$")):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
self.cm.request("clk20", 0)
|
2019-07-03 09:07:44 -06:00
|
|
|
|
2019-04-26 06:37:08 -06:00
|
|
|
def test_wrong_request_with_dir(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
(r"^Direction must be one of \"i\", \"o\", \"oe\", \"io\", or \"-\", "
|
|
|
|
r"not 'wrong'$")):
|
2019-04-26 06:37:08 -06:00
|
|
|
user_led = self.cm.request("user_led", 0, dir="wrong")
|
|
|
|
|
|
|
|
def test_wrong_request_with_dir_io(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
(r"^Direction of \(pins o A0\) cannot be changed from \"o\" to \"i\"; direction "
|
|
|
|
r"can be changed from \"io\" to \"i\", \"o\", or \"oe\", or from anything "
|
|
|
|
r"to \"-\"$")):
|
2019-04-26 06:37:08 -06:00
|
|
|
user_led = self.cm.request("user_led", 0, dir="i")
|
|
|
|
|
|
|
|
def test_wrong_request_with_dir_dict(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
(r"^Directions must be a dict, not 'i', because \(resource i2c 0 \(subsignal scl "
|
|
|
|
r"\(pins o N10\)\) \(subsignal sda \(pins io N11\)\)\) "
|
|
|
|
r"has subsignals$")):
|
2019-04-26 06:37:08 -06:00
|
|
|
i2c = self.cm.request("i2c", 0, dir="i")
|
|
|
|
|
|
|
|
def test_wrong_request_with_wrong_xdr(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
r"^Data rate of \(pins o A0\) must be a non-negative integer, not -1$"):
|
2019-06-02 21:32:30 -06:00
|
|
|
user_led = self.cm.request("user_led", 0, xdr=-1)
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_wrong_request_with_xdr_dict(self):
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
|
|
r"^Data rate must be a dict, not 2, because \(resource i2c 0 \(subsignal scl "
|
|
|
|
r"\(pins o N10\)\) \(subsignal sda \(pins io N11\)\)\) "
|
|
|
|
r"has subsignals$"):
|
2019-04-26 06:37:08 -06:00
|
|
|
i2c = self.cm.request("i2c", 0, xdr=2)
|
2019-06-05 02:48:36 -06:00
|
|
|
|
|
|
|
def test_wrong_clock_constraint_twice(self):
|
2024-04-10 23:45:53 -06:00
|
|
|
with _ignore_deprecated():
|
|
|
|
clk100 = self.cm.request("clk100")
|
2024-04-13 02:32:46 -06:00
|
|
|
(pin, port, buffer), = self.cm.iter_pins()
|
|
|
|
buffer._MustUse__silence = True
|
2020-07-28 13:35:25 -06:00
|
|
|
with self.assertRaisesRegex(ValueError,
|
|
|
|
(r"^Cannot add clock constraint on \(sig clk100_0__i\), which is already "
|
|
|
|
r"constrained to 100000000\.0 Hz$")):
|
build.res: simplify clock constraints.
Before this commit, it was possible to set and get clock constraints
placed on Pin objects. This was not a very good implementation, since
it relied on matching the identity of the provided Pin object to
a previously requested one. The only reason it worked like that is
deficiencies in nextpnr.
Since then, nextpnr has been fixed to allow setting constraints on
arbitrary nets. Correspondingly, backends that are using Synplify
were changed to use [get_nets] instead of [get_ports] in SDC files.
However, in some situations, Synplify does not allow specifying
ports in [get_nets]. (In fact, nextpnr had a similar problem, but
it has also been fixed.)
The simplest way to address this is to refer to the interior net
(after the input buffer), which always works. The only downside
of this is that requesting a clock as a raw pin using
platform.request("clk", dir="-")
and directly applying a constraint to it could fail in some cases.
This is not a significant issue.
2019-09-21 08:12:29 -06:00
|
|
|
self.cm.add_clock_constraint(clk100.i, 1e6)
|