for pin, p_port, n_port, extras in self.iter_differential_pins():
if pin.dir == "i":
- add_pin_fragment(pin, self.get_diff_input(pin, p_port, n_port))
+ add_pin_fragment(pin, self.get_diff_input(pin, p_port, n_port, extras))
if pin.dir == "o":
- add_pin_fragment(pin, self.get_diff_output(pin, p_port, n_port))
+ add_pin_fragment(pin, self.get_diff_output(pin, p_port, n_port, extras))
if pin.dir == "oe":
- add_pin_fragment(pin, self.get_diff_tristate(pin, p_port, n_port))
+ add_pin_fragment(pin, self.get_diff_tristate(pin, p_port, n_port, extras))
if pin.dir == "io":
- add_pin_fragment(pin, self.get_diff_input_output(pin, p_port, n_port))
+ add_pin_fragment(pin, self.get_diff_input_output(pin, p_port, n_port, extras))
return self.toolchain_prepare(fragment, name, **kwargs)
else:
assert False
- def iter_port_constraints(self, diff_pins="pn"):
+ def iter_port_constraints(self):
for resource, pin, port in self._ports:
if isinstance(resource.io[0], Pins):
yield port.io.name, resource.io[0].names, resource.extras
elif isinstance(resource.io[0], DiffPairs):
- # 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.
- if "p" in diff_pins:
- yield port.p.name, resource.io[0].p.names, resource.extras
- if "n" in diff_pins:
- yield port.n.name, resource.io[0].n.names, resource.extras
+ yield port.p.name, resource.io[0].p.names, resource.extras
+ yield port.n.name, resource.io[0].n.names, resource.extras
else:
assert False
("clk100_0__p", ["H1"], {}),
("clk100_0__n", ["H2"], {}),
])
- self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="p")), [
- ("clk100_0__p", ["H1"], {}),
- ])
- self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="n")), [
- ("clk100_0__n", ["H2"], {}),
- ])
def test_request_raw(self):
clk50 = self.cm.request("clk50", 0, dir="-")
"""
]
+ def iter_ports(self):
+ for resource, pin, port in self._ports:
+ if isinstance(resource.io[0], Pins):
+ yield port.io
+ elif isinstance(resource.io[0], DiffPairs):
+ if resource.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT":
+ yield port.p
+ else:
+ yield port.p
+ yield port.n
+ else:
+ assert False
+
+ def iter_port_constraints(self):
+ for resource, pin, port in self._ports:
+ if isinstance(resource.io[0], Pins):
+ yield port.io.name, resource.io[0].names, resource.extras
+ elif isinstance(resource.io[0], DiffPairs):
+ if resource.extras.get("IO_STANDARD", "SB_LVCMOS") == "SB_LVDS_INPUT":
+ yield port.p.name, resource.io[0].p.names, resource.extras
+ else:
+ yield port.p.name, resource.io[0].p.names, resource.extras
+ yield port.n.name, resource.io[0].n.names, resource.extras
+ else:
+ assert False
+
def _get_dff(self, clk, d, q):
return Instance("$dff",
p_CLK_POLARITY=0,
valid_xdrs=(0, 1, 2), valid_extras=True)
return self._get_io_buffer(pin, port, extras)
+ def get_diff_input(self, pin, p_port, n_port, extras):
+ self._check_feature("differential input", pin, extras,
+ valid_xdrs=(0, 1, 2), valid_extras=True)
+ # On iCE40, a differential input is placed by only instantiating an SB_IO primitive for
+ # the pin with z=0, which is the non-inverting pin. The pinout unfortunately differs
+ # between LP/HX and UP series:
+ # * for LP/HX, z=0 is DPxxB (B is non-inverting, A is inverting)
+ # * for UP, z=0 is IOB_xxA (A is non-inverting, B is inverting)
+ return self._get_io_buffer(pin, p_port, extras)
+
class IceStormProgrammerMixin:
def toolchain_program(self, products, name, *, mode=None):