build.res: allow requesting raw ports, with dir="-".
This provides an escape hatch for the case where the nMigen platform code is not flexible enough, and a IO buffer primitive needs to be instantiated directly.
This commit is contained in:
parent
c30617fc05
commit
cd6488c782
|
@ -84,13 +84,14 @@ class ConstraintManager:
|
||||||
dir = subsignal.io[0].dir
|
dir = subsignal.io[0].dir
|
||||||
if xdr is None:
|
if xdr is None:
|
||||||
xdr = 1
|
xdr = 1
|
||||||
if dir not in ("i", "o", "io"):
|
if dir not in ("i", "o", "io", "-"):
|
||||||
raise TypeError("Direction must be one of \"i\", \"o\" or \"io\", not {!r}"
|
raise TypeError("Direction must be one of \"i\", \"o\", \"io\", or \"-\", "
|
||||||
|
"not {!r}"
|
||||||
.format(dir))
|
.format(dir))
|
||||||
if subsignal.io[0].dir != "io" and dir != subsignal.io[0].dir:
|
if dir != subsignal.io[0].dir and not (subsignal.io[0].dir == "io" or dir == "-"):
|
||||||
raise ValueError("Direction of {!r} cannot be changed from \"{}\" to \"{}\"; "
|
raise ValueError("Direction of {!r} cannot be changed from \"{}\" to \"{}\"; "
|
||||||
"direction can be changed from \"io\" to \"i\" or from \"io\""
|
"direction can be changed from \"io\" to \"i\", from \"io\""
|
||||||
"to \"o\""
|
"to \"o\", or from anything to \"-\""
|
||||||
.format(subsignal.io[0], subsignal.io[0].dir, dir))
|
.format(subsignal.io[0], subsignal.io[0].dir, dir))
|
||||||
if not isinstance(xdr, int) or xdr < 1:
|
if not isinstance(xdr, int) or xdr < 1:
|
||||||
raise ValueError("Data rate of {!r} must be a positive integer, not {!r}"
|
raise ValueError("Data rate of {!r} must be a positive integer, not {!r}"
|
||||||
|
@ -109,14 +110,19 @@ class ConstraintManager:
|
||||||
|
|
||||||
elif isinstance(subsignal.io[0], (Pins, DiffPairs)):
|
elif isinstance(subsignal.io[0], (Pins, DiffPairs)):
|
||||||
phys = subsignal.io[0]
|
phys = subsignal.io[0]
|
||||||
pin = Pin(len(phys), dir, xdr, name=name)
|
|
||||||
if isinstance(phys, Pins):
|
if isinstance(phys, Pins):
|
||||||
port = Signal(pin.width, name="{}__io".format(pin.name))
|
port = Record([("io", len(phys))], name=name)
|
||||||
if isinstance(phys, DiffPairs):
|
if isinstance(phys, DiffPairs):
|
||||||
port = (Signal(pin.width, name="{}__p".format(pin.name)),
|
port = Record([("p", len(phys)),
|
||||||
Signal(pin.width, name="{}__n".format(pin.name)))
|
("n", len(phys))], name=name)
|
||||||
self._ports.append((subsignal, pin, port))
|
if dir == "-":
|
||||||
return pin
|
self._ports.append((subsignal, None, port))
|
||||||
|
return port
|
||||||
|
else:
|
||||||
|
pin = Pin(len(phys), dir, xdr, name=name)
|
||||||
|
self._ports.append((subsignal, pin, port))
|
||||||
|
return pin
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assert False # :nocov:
|
assert False # :nocov:
|
||||||
|
|
||||||
|
@ -128,38 +134,39 @@ class ConstraintManager:
|
||||||
|
|
||||||
def iter_single_ended_pins(self):
|
def iter_single_ended_pins(self):
|
||||||
for resource, pin, port in self._ports:
|
for resource, pin, port in self._ports:
|
||||||
|
if pin is None:
|
||||||
|
continue
|
||||||
if isinstance(resource.io[0], Pins):
|
if isinstance(resource.io[0], Pins):
|
||||||
yield pin, port, resource.extras
|
yield pin, port.io, resource.extras
|
||||||
|
|
||||||
def iter_differential_pins(self):
|
def iter_differential_pins(self):
|
||||||
for resource, pin, port in self._ports:
|
for resource, pin, port in self._ports:
|
||||||
|
if pin is None:
|
||||||
|
continue
|
||||||
if isinstance(resource.io[0], DiffPairs):
|
if isinstance(resource.io[0], DiffPairs):
|
||||||
p_port, n_port = port
|
yield pin, port.p, port.n, resource.extras
|
||||||
yield pin, p_port, n_port, resource.extras
|
|
||||||
|
|
||||||
def iter_ports(self):
|
def iter_ports(self):
|
||||||
for resource, pin, port in self._ports:
|
for resource, pin, port in self._ports:
|
||||||
if isinstance(resource.io[0], Pins):
|
if isinstance(resource.io[0], Pins):
|
||||||
yield port
|
yield port.io
|
||||||
elif isinstance(resource.io[0], DiffPairs):
|
elif isinstance(resource.io[0], DiffPairs):
|
||||||
p_port, n_port = port
|
yield port.p
|
||||||
yield p_port
|
yield port.n
|
||||||
yield n_port
|
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
def iter_port_constraints(self, diff_pins="pn"):
|
def iter_port_constraints(self, diff_pins="pn"):
|
||||||
for resource, pin, port in self._ports:
|
for resource, pin, port in self._ports:
|
||||||
if isinstance(resource.io[0], Pins):
|
if isinstance(resource.io[0], Pins):
|
||||||
yield port.name, resource.io[0].names, resource.extras
|
yield port.io.name, resource.io[0].names, resource.extras
|
||||||
elif isinstance(resource.io[0], DiffPairs):
|
elif isinstance(resource.io[0], DiffPairs):
|
||||||
p_port, n_port = port
|
|
||||||
# On some FPGAs like iCE40, only one pin out of two in a differential pair may be
|
# On some FPGAs like iCE40, only one pin out of two in a differential pair may be
|
||||||
# constrained. The other has to be completely disconnected.
|
# constrained. The other has to be completely disconnected.
|
||||||
if "p" in diff_pins:
|
if "p" in diff_pins:
|
||||||
yield p_port.name, resource.io[0].p.names, resource.extras
|
yield port.p.name, resource.io[0].p.names, resource.extras
|
||||||
if "n" in diff_pins:
|
if "n" in diff_pins:
|
||||||
yield n_port.name, resource.io[0].n.names, resource.extras
|
yield port.n.name, resource.io[0].n.names, resource.extras
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,26 @@ class ConstraintManagerTestCase(FHDLTestCase):
|
||||||
("clk100_0__n", ["H2"], {}),
|
("clk100_0__n", ["H2"], {}),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_request_raw(self):
|
||||||
|
clk50 = self.cm.request("clk50", 0, dir="-")
|
||||||
|
self.assertIsInstance(clk50, Record)
|
||||||
|
self.assertIsInstance(clk50.io, Signal)
|
||||||
|
|
||||||
|
ports = list(self.cm.iter_ports())
|
||||||
|
self.assertEqual(len(ports), 1)
|
||||||
|
self.assertIs(ports[0], clk50.io)
|
||||||
|
|
||||||
|
def test_request_raw_diffpairs(self):
|
||||||
|
clk100 = self.cm.request("clk100", 0, dir="-")
|
||||||
|
self.assertIsInstance(clk100, Record)
|
||||||
|
self.assertIsInstance(clk100.p, Signal)
|
||||||
|
self.assertIsInstance(clk100.n, Signal)
|
||||||
|
|
||||||
|
ports = list(self.cm.iter_ports())
|
||||||
|
self.assertEqual(len(ports), 2)
|
||||||
|
self.assertIs(ports[0], clk100.p)
|
||||||
|
self.assertIs(ports[1], clk100.n)
|
||||||
|
|
||||||
def test_add_clock(self):
|
def test_add_clock(self):
|
||||||
self.cm.add_clock("clk100", 0, 10e6)
|
self.cm.add_clock("clk100", 0, 10e6)
|
||||||
self.assertEqual(self.cm.clocks["clk100", 0], 10e6)
|
self.assertEqual(self.cm.clocks["clk100", 0], 10e6)
|
||||||
|
@ -177,13 +197,14 @@ class ConstraintManagerTestCase(FHDLTestCase):
|
||||||
|
|
||||||
def test_wrong_request_with_dir(self):
|
def test_wrong_request_with_dir(self):
|
||||||
with self.assertRaises(TypeError,
|
with self.assertRaises(TypeError,
|
||||||
msg="Direction must be one of \"i\", \"o\" or \"io\", not 'wrong'"):
|
msg="Direction must be one of \"i\", \"o\", \"io\", or \"-\", not 'wrong'"):
|
||||||
user_led = self.cm.request("user_led", 0, dir="wrong")
|
user_led = self.cm.request("user_led", 0, dir="wrong")
|
||||||
|
|
||||||
def test_wrong_request_with_dir_io(self):
|
def test_wrong_request_with_dir_io(self):
|
||||||
with self.assertRaises(ValueError,
|
with self.assertRaises(ValueError,
|
||||||
msg="Direction of (pins o A0) cannot be changed from \"o\" to \"i\"; direction "
|
msg="Direction of (pins o A0) cannot be changed from \"o\" to \"i\"; direction "
|
||||||
"can be changed from \"io\" to \"i\" or from \"io\"to \"o\""):
|
"can be changed from \"io\" to \"i\", from \"io\"to \"o\", or from anything "
|
||||||
|
"to \"-\""):
|
||||||
user_led = self.cm.request("user_led", 0, dir="i")
|
user_led = self.cm.request("user_led", 0, dir="i")
|
||||||
|
|
||||||
def test_wrong_request_with_dir_dict(self):
|
def test_wrong_request_with_dir_dict(self):
|
||||||
|
|
Loading…
Reference in a new issue