Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b8a61edc2fc3
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f417725b10de
Choose a head ref
  • 3 commits
  • 6 files changed
  • 1 contributor

Commits on Jun 3, 2019

  1. hdl.ir: accept LHS signals like slices as Instance io ports.

    This is unlikely to work with anything except Slice and Cat, but
    there's no especially good place to enforce it. (Maybe in Instance?)
    whitequark committed Jun 3, 2019
    Copy the full SHA
    c6a0761 View commit details
  2. 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.
    whitequark committed Jun 3, 2019
    Copy the full SHA
    dc17d06 View commit details
  3. build.res: if not specified, request resource #0.

    This markedly differs from oMigen system, which would request
    consecutive resources. The difference is deliberate; most resources
    are singular, so it does not matter for them, and for resources where
    it does matter, which pins are requested should not depend on order
    of execution of `platform.request`.
    whitequark committed Jun 3, 2019
    Copy the full SHA
    f417725 View commit details
Showing with 64 additions and 26 deletions.
  1. +1 −1 examples/blinky.py
  2. +7 −7 nmigen/build/res.py
  3. +8 −5 nmigen/hdl/ir.py
  4. +12 −12 nmigen/test/test_build_res.py
  5. +1 −1 nmigen/test/test_hdl_ir.py
  6. +35 −0 nmigen/vendor/fpga/lattice_ice40.py
2 changes: 1 addition & 1 deletion examples/blinky.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@

class Blinky(Elaboratable):
def elaborate(self, platform):
clk3p3 = platform.request("clk3p3", 0)
clk3p3 = platform.request("clk3p3")
user_led = platform.request("user_led", 0)
counter = Signal(20)

14 changes: 7 additions & 7 deletions nmigen/build/res.py
Original file line number Diff line number Diff line change
@@ -49,13 +49,13 @@ def add_clock(self, name, number, frequency):
.format(resource.name, resource.number, other / 1e6))
self.clocks[resource.name, resource.number] = frequency

def lookup(self, name, number):
def lookup(self, name, number=0):
if (name, number) not in self.resources:
raise NameError("Resource {}#{} does not exist"
.format(name, number))
return self.resources[name, number]

def request(self, name, number, dir=None, xdr=None):
def request(self, name, number=0, *, dir=None, xdr=None):
resource = self.lookup(name, number)
if (resource.name, resource.number) in self.requested:
raise ConstraintError("Resource {}#{} has already been requested"
@@ -111,10 +111,10 @@ def resolve(subsignal, dir, xdr, name):
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 @@ def iter_clock_constraints(self):
"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)
13 changes: 8 additions & 5 deletions nmigen/hdl/ir.py
Original file line number Diff line number Diff line change
@@ -373,9 +373,12 @@ def add_defs(*sigs):
else:
assert defs[sig] is self

def add_io(sig):
assert sig not in ios
ios[sig] = self
def add_io(*sigs):
for sig in flatten(sigs):
if sig not in ios:
ios[sig] = self
else:
assert ios[sig] is self

# Collect all signals we're driving (on LHS of statements), and signals we're using
# (on RHS of statements, or in clock domains).
@@ -400,8 +403,8 @@ def add_io(sig):
subfrag.add_ports(value._lhs_signals(), dir=dir)
add_defs(value._lhs_signals())
if dir == "io":
subfrag.add_ports(value, dir=dir)
add_io(value)
subfrag.add_ports(value._lhs_signals(), dir=dir)
add_io(value._lhs_signals())
else:
parent[subfrag] = self
level [subfrag] = level[self] + 1
24 changes: 12 additions & 12 deletions nmigen/test/test_build_res.py
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ def test_request_basic(self):
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,16 +82,16 @@ def test_request_tristate(self):
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()), [
(i2c.scl, scl, {}),
(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 @@ def test_request_diffpairs(self):
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 @@ def test_add_clock(self):
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):
2 changes: 1 addition & 1 deletion nmigen/test/test_hdl_ir.py
Original file line number Diff line number Diff line change
@@ -603,7 +603,7 @@ def setUp_cpu(self):
i_rst=self.rst,
o_stb=self.stb,
o_data=Cat(self.datal, self.datah),
io_pins=self.pins
io_pins=self.pins[:]
)
self.wrap = Fragment()
self.wrap.add_subfragment(self.inst)
35 changes: 35 additions & 0 deletions nmigen/vendor/fpga/lattice_ice40.py
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@
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):