From dc17d06fe98c5266b0c024e963a83436c3fca3f6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 3 Jun 2019 02:48:55 +0000 Subject: [PATCH] vendor.fpga.lattice_ice40: instantiate SB_IO and apply extras. The PULLUP and PULLUP_RESISTOR extras are representable in the PCF file. The IO_STANDARD extra, however, can only be an SB_IO parameter. --- nmigen/build/res.py | 10 ++++----- nmigen/test/test_build_res.py | 24 ++++++++++---------- nmigen/vendor/fpga/lattice_ice40.py | 35 +++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/nmigen/build/res.py b/nmigen/build/res.py index 5ac3c64..9376f00 100644 --- a/nmigen/build/res.py +++ b/nmigen/build/res.py @@ -111,10 +111,10 @@ class ConstraintManager: phys = subsignal.io[0] pin = Pin(len(phys), dir, xdr, name=name) if isinstance(phys, Pins): - port = Signal(pin.width, name="{}_io".format(pin.name)) + port = Signal(pin.width, name="{}__io".format(pin.name)) if isinstance(phys, DiffPairs): - port = (Signal(pin.width, name="{}_p".format(pin.name)), - Signal(pin.width, name="{}_n".format(pin.name))) + port = (Signal(pin.width, name="{}__p".format(pin.name)), + Signal(pin.width, name="{}__n".format(pin.name))) self._ports.append((subsignal, pin, port)) return pin else: @@ -173,9 +173,9 @@ class ConstraintManager: "it has been requested as a tristate buffer" .format(name, number)) if isinstance(resource.io[0], Pins): - port_name = "{}_io".format(pin.name) + port_name = "{}__io".format(pin.name) elif isinstance(resource.io[0], DiffPairs): - port_name = "{}_p".format(pin.name) + port_name = "{}__p".format(pin.name) else: assert False yield (port_name, period) diff --git a/nmigen/test/test_build_res.py b/nmigen/test/test_build_res.py index 26acc7c..13b3042 100644 --- a/nmigen/test/test_build_res.py +++ b/nmigen/test/test_build_res.py @@ -66,7 +66,7 @@ class ConstraintManagerTestCase(FHDLTestCase): self.assertEqual(len(ports), 1) self.assertEqual(list(self.cm.iter_port_constraints()), [ - ("user_led_0_io", ["A0"], {}) + ("user_led_0__io", ["A0"], {}) ]) def test_request_with_dir(self): @@ -82,7 +82,7 @@ class ConstraintManagerTestCase(FHDLTestCase): ports = list(self.cm.iter_ports()) self.assertEqual(len(ports), 2) scl, sda = ports - self.assertEqual(ports[1].name, "i2c_0__sda_io") + self.assertEqual(ports[1].name, "i2c_0__sda__io") self.assertEqual(ports[1].nbits, 1) self.assertEqual(list(self.cm.iter_single_ended_pins()), [ @@ -90,8 +90,8 @@ class ConstraintManagerTestCase(FHDLTestCase): (i2c.sda, sda, {}), ]) self.assertEqual(list(self.cm.iter_port_constraints()), [ - ("i2c_0__scl_io", ["N10"], {}), - ("i2c_0__sda_io", ["N11"], {}) + ("i2c_0__scl__io", ["N10"], {}), + ("i2c_0__sda__io", ["N11"], {}) ]) def test_request_diffpairs(self): @@ -103,23 +103,23 @@ class ConstraintManagerTestCase(FHDLTestCase): ports = list(self.cm.iter_ports()) self.assertEqual(len(ports), 2) p, n = ports - self.assertEqual(p.name, "clk100_0_p") + self.assertEqual(p.name, "clk100_0__p") self.assertEqual(p.nbits, clk100.width) - self.assertEqual(n.name, "clk100_0_n") + self.assertEqual(n.name, "clk100_0__n") self.assertEqual(n.nbits, clk100.width) self.assertEqual(list(self.cm.iter_differential_pins()), [ (clk100, p, n, {}), ]) self.assertEqual(list(self.cm.iter_port_constraints()), [ - ("clk100_0_p", ["H1"], {}), - ("clk100_0_n", ["H2"], {}), + ("clk100_0__p", ["H1"], {}), + ("clk100_0__n", ["H2"], {}), ]) self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="p")), [ - ("clk100_0_p", ["H1"], {}), + ("clk100_0__p", ["H1"], {}), ]) self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="n")), [ - ("clk100_0_n", ["H2"], {}), + ("clk100_0__n", ["H2"], {}), ]) def test_add_clock(self): @@ -130,8 +130,8 @@ class ConstraintManagerTestCase(FHDLTestCase): clk100 = self.cm.request("clk100", 0) clk50 = self.cm.request("clk50", 0, dir="i") self.assertEqual(list(sorted(self.cm.iter_clock_constraints())), [ - ("clk100_0_p", 10e6), - ("clk50_0_io", 5e6) + ("clk100_0__p", 10e6), + ("clk50_0__io", 5e6) ]) def test_wrong_resources(self): diff --git a/nmigen/vendor/fpga/lattice_ice40.py b/nmigen/vendor/fpga/lattice_ice40.py index ab6c2a2..9a8469c 100644 --- a/nmigen/vendor/fpga/lattice_ice40.py +++ b/nmigen/vendor/fpga/lattice_ice40.py @@ -3,6 +3,9 @@ import os import subprocess import tempfile +from ...hdl.ast import * +from ...hdl.dsl import * +from ...hdl.ir import * from ...build import * @@ -104,6 +107,38 @@ class LatticeICE40Platform(TemplatedPlatform): """ ] + def _get_io_buffer(self, port, extras, fn): + m = Module() + for bit in range(len(port)): + m.submodules += Instance("SB_IO", + ("io", "PACKAGE_PIN", port[bit]), + *fn(bit), + *(("p", key, value) for key, value in extras.items())) + return m + + def get_input(self, pin, port, extras): + return self._get_io_buffer(port, extras, lambda bit: [ + # PIN_NO_OUTPUT|PIN_INPUT + ("p", "PIN_TYPE", 0b0000_01), + ("o", "D_IN_0", pin.i[bit]), + ]) + + def get_output(self, pin, port, extras): + return self._get_io_buffer(port, extras, lambda bit: [ + # PIN_OUTPUT|PIN_INPUT_REGISTERED + ("p", "PIN_TYPE", 0b0110_00), + ("i", "D_OUT_0", pin.o[bit]), + ]) + + def get_tristate(self, pin, port, extras): + return self._get_io_buffer(port, extras, lambda bit: [ + # PIN_OUTPUT_TRISTATE|PIN_INPUT_REGISTERED + ("p", "PIN_TYPE", 0b1010_00), + ("o", "D_IN_0", pin.i[bit]), + ("i", "D_OUT_0", pin.o[bit]), + ("i", "OUTPUT_ENABLE", pin.oe), + ]) + class IceStormProgrammerMixin: def toolchain_program(self, products, name, *, mode=None): -- 2.30.2