From 41adcc3f9758b3f416b4116a1e532f8899620946 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 3 Jun 2019 08:38:12 +0000 Subject: [PATCH] vendor.fpga.lattice_ice40: implement differential input buffers. --- nmigen/build/plat.py | 8 +++---- nmigen/build/res.py | 10 +++----- nmigen/test/test_build_res.py | 6 ----- nmigen/vendor/fpga/lattice_ice40.py | 36 +++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/nmigen/build/plat.py b/nmigen/build/plat.py index 0dfa752..6b4ee30 100644 --- a/nmigen/build/plat.py +++ b/nmigen/build/plat.py @@ -134,13 +134,13 @@ class Platform(ConstraintManager, metaclass=ABCMeta): 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) diff --git a/nmigen/build/res.py b/nmigen/build/res.py index 4985293..9cea237 100644 --- a/nmigen/build/res.py +++ b/nmigen/build/res.py @@ -156,17 +156,13 @@ class ConstraintManager: 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 diff --git a/nmigen/test/test_build_res.py b/nmigen/test/test_build_res.py index c7cff57..d81584b 100644 --- a/nmigen/test/test_build_res.py +++ b/nmigen/test/test_build_res.py @@ -115,12 +115,6 @@ class ConstraintManagerTestCase(FHDLTestCase): ("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="-") diff --git a/nmigen/vendor/fpga/lattice_ice40.py b/nmigen/vendor/fpga/lattice_ice40.py index b8852d1..3ae605c 100644 --- a/nmigen/vendor/fpga/lattice_ice40.py +++ b/nmigen/vendor/fpga/lattice_ice40.py @@ -108,6 +108,32 @@ class LatticeICE40Platform(TemplatedPlatform): """ ] + 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, @@ -216,6 +242,16 @@ class LatticeICE40Platform(TemplatedPlatform): 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): -- 2.30.2