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.
This commit is contained in:
whitequark 2019-06-03 02:48:55 +00:00
parent c6a0761b3a
commit dc17d06fe9
3 changed files with 52 additions and 17 deletions

View file

@ -111,10 +111,10 @@ class ConstraintManager:
phys = subsignal.io[0] phys = subsignal.io[0]
pin = Pin(len(phys), dir, xdr, name=name) 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 = Signal(pin.width, name="{}__io".format(pin.name))
if isinstance(phys, DiffPairs): if isinstance(phys, DiffPairs):
port = (Signal(pin.width, name="{}_p".format(pin.name)), port = (Signal(pin.width, name="{}__p".format(pin.name)),
Signal(pin.width, name="{}_n".format(pin.name))) Signal(pin.width, name="{}__n".format(pin.name)))
self._ports.append((subsignal, pin, port)) self._ports.append((subsignal, pin, port))
return pin return pin
else: else:
@ -173,9 +173,9 @@ class ConstraintManager:
"it has been requested as a tristate buffer" "it has been requested as a tristate buffer"
.format(name, number)) .format(name, number))
if isinstance(resource.io[0], Pins): if isinstance(resource.io[0], Pins):
port_name = "{}_io".format(pin.name) port_name = "{}__io".format(pin.name)
elif isinstance(resource.io[0], DiffPairs): elif isinstance(resource.io[0], DiffPairs):
port_name = "{}_p".format(pin.name) port_name = "{}__p".format(pin.name)
else: else:
assert False assert False
yield (port_name, period) yield (port_name, period)

View file

@ -66,7 +66,7 @@ class ConstraintManagerTestCase(FHDLTestCase):
self.assertEqual(len(ports), 1) self.assertEqual(len(ports), 1)
self.assertEqual(list(self.cm.iter_port_constraints()), [ self.assertEqual(list(self.cm.iter_port_constraints()), [
("user_led_0_io", ["A0"], {}) ("user_led_0__io", ["A0"], {})
]) ])
def test_request_with_dir(self): def test_request_with_dir(self):
@ -82,7 +82,7 @@ class ConstraintManagerTestCase(FHDLTestCase):
ports = list(self.cm.iter_ports()) ports = list(self.cm.iter_ports())
self.assertEqual(len(ports), 2) self.assertEqual(len(ports), 2)
scl, sda = ports 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(ports[1].nbits, 1)
self.assertEqual(list(self.cm.iter_single_ended_pins()), [ self.assertEqual(list(self.cm.iter_single_ended_pins()), [
@ -90,8 +90,8 @@ class ConstraintManagerTestCase(FHDLTestCase):
(i2c.sda, sda, {}), (i2c.sda, sda, {}),
]) ])
self.assertEqual(list(self.cm.iter_port_constraints()), [ self.assertEqual(list(self.cm.iter_port_constraints()), [
("i2c_0__scl_io", ["N10"], {}), ("i2c_0__scl__io", ["N10"], {}),
("i2c_0__sda_io", ["N11"], {}) ("i2c_0__sda__io", ["N11"], {})
]) ])
def test_request_diffpairs(self): def test_request_diffpairs(self):
@ -103,23 +103,23 @@ class ConstraintManagerTestCase(FHDLTestCase):
ports = list(self.cm.iter_ports()) ports = list(self.cm.iter_ports())
self.assertEqual(len(ports), 2) self.assertEqual(len(ports), 2)
p, n = ports 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(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(n.nbits, clk100.width)
self.assertEqual(list(self.cm.iter_differential_pins()), [ self.assertEqual(list(self.cm.iter_differential_pins()), [
(clk100, p, n, {}), (clk100, p, n, {}),
]) ])
self.assertEqual(list(self.cm.iter_port_constraints()), [ self.assertEqual(list(self.cm.iter_port_constraints()), [
("clk100_0_p", ["H1"], {}), ("clk100_0__p", ["H1"], {}),
("clk100_0_n", ["H2"], {}), ("clk100_0__n", ["H2"], {}),
]) ])
self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="p")), [ 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")), [ self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="n")), [
("clk100_0_n", ["H2"], {}), ("clk100_0__n", ["H2"], {}),
]) ])
def test_add_clock(self): def test_add_clock(self):
@ -130,8 +130,8 @@ class ConstraintManagerTestCase(FHDLTestCase):
clk100 = self.cm.request("clk100", 0) clk100 = self.cm.request("clk100", 0)
clk50 = self.cm.request("clk50", 0, dir="i") clk50 = self.cm.request("clk50", 0, dir="i")
self.assertEqual(list(sorted(self.cm.iter_clock_constraints())), [ self.assertEqual(list(sorted(self.cm.iter_clock_constraints())), [
("clk100_0_p", 10e6), ("clk100_0__p", 10e6),
("clk50_0_io", 5e6) ("clk50_0__io", 5e6)
]) ])
def test_wrong_resources(self): def test_wrong_resources(self):

View file

@ -3,6 +3,9 @@ import os
import subprocess import subprocess
import tempfile import tempfile
from ...hdl.ast import *
from ...hdl.dsl import *
from ...hdl.ir import *
from ...build 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: class IceStormProgrammerMixin:
def toolchain_program(self, products, name, *, mode=None): def toolchain_program(self, products, name, *, mode=None):