vendor.fpga.lattice_ice40: implement SDR and DDR I/O buffers.
This commit is contained in:
parent
b42043f764
commit
185abb492d
111
nmigen/vendor/fpga/lattice_ice40.py
vendored
111
nmigen/vendor/fpga/lattice_ice40.py
vendored
|
@ -108,53 +108,102 @@ class LatticeICE40Platform(TemplatedPlatform):
|
|||
"""
|
||||
]
|
||||
|
||||
def _get_io_buffer(self, port, extras, fn):
|
||||
def _get_dff(self, clk, d, q):
|
||||
return Instance("$dff",
|
||||
p_CLK_POLARITY=0,
|
||||
p_WIDTH=len(d),
|
||||
i_CLK=clk,
|
||||
i_D=d,
|
||||
o_Q=q)
|
||||
|
||||
def _get_io_buffer(self, pin, port, extras):
|
||||
m = Module()
|
||||
|
||||
if "i" in pin.dir and pin.xdr == 2:
|
||||
i0_ff = Signal.like(pin.i0, name="{}_ff".format(pin.i0.name))
|
||||
i1_ff = Signal.like(pin.i1, name="{}_ff".format(pin.i1.name))
|
||||
m.submodules += self._get_dff(pin.i_clk, i0_ff, pin.i0)
|
||||
m.submodules += self._get_dff(pin.i_clk, i1_ff, pin.i1)
|
||||
if "o" in pin.dir and pin.xdr == 2:
|
||||
o1_ff = Signal.like(pin.o1, name="{}_ff".format(pin.o1.name))
|
||||
m.submodules += self._get_dff(pin.o_clk, pin.o1, o1_ff)
|
||||
|
||||
for bit in range(len(port)):
|
||||
m.submodules += Instance("SB_IO",
|
||||
io_args = [
|
||||
("io", "PACKAGE_PIN", port[bit]),
|
||||
*fn(bit),
|
||||
*(("p", key, value) for key, value in extras.items()))
|
||||
*(("p", key, value) for key, value in extras.items()),
|
||||
]
|
||||
|
||||
if "i" not in pin.dir:
|
||||
i_type = 0b00 # PIN_NO_INPUT aka PIN_INPUT_REGISTERED
|
||||
elif pin.xdr == 0:
|
||||
i_type = 0b01 # PIN_INPUT
|
||||
elif pin.xdr > 0:
|
||||
i_type = 0b00 # PIN_INPUT_REGISTERED
|
||||
if "o" not in pin.dir:
|
||||
o_type = 0b0000 # PIN_NO_OUTPUT
|
||||
elif pin.xdr == 0 and pin.dir == "o":
|
||||
o_type = 0b0110 # PIN_OUTPUT
|
||||
elif pin.xdr == 0:
|
||||
o_type = 0b1010 # PIN_OUTPUT_TRISTATE
|
||||
elif pin.xdr == 1 and pin.dir == "o":
|
||||
o_type = 0b0101 # PIN_OUTPUT_REGISTERED
|
||||
elif pin.xdr == 1:
|
||||
o_type = 0b1101 # PIN_OUTPUT_REGISTERED_ENABLE_REGISTERED
|
||||
elif pin.xdr == 2 and pin.dir == "o":
|
||||
o_type = 0b0100 # PIN_OUTPUT_DDR
|
||||
elif pin.xdr == 2:
|
||||
o_type = 0b1100 # PIN_OUTPUT_DDR_ENABLE_REGISTERED
|
||||
io_args.append(("p", "PIN_TYPE", (o_type << 2) | i_type))
|
||||
|
||||
if hasattr(pin, "i_clk"):
|
||||
io_args.append(("i", "INPUT_CLK", pin.i_clk))
|
||||
if hasattr(pin, "o_clk"):
|
||||
io_args.append(("i", "OUTPUT_CLK", pin.o_clk))
|
||||
|
||||
if "i" in pin.dir:
|
||||
if pin.xdr < 2:
|
||||
io_args.append(("o", "D_IN_0", pin.i[bit]))
|
||||
if pin.xdr == 2:
|
||||
# Re-register both inputs before they enter fabric. This increases hold time
|
||||
# to an entire cycle, and adds one cycle of latency.
|
||||
io_args.append(("o", "D_IN_0", i0_ff))
|
||||
io_args.append(("o", "D_IN_1", i1_ff))
|
||||
if "o" in pin.dir:
|
||||
if pin.xdr < 2:
|
||||
io_args.append(("i", "D_OUT_0", pin.o[bit]))
|
||||
if pin.xdr == 2:
|
||||
# Re-register negedge output after it leaves fabric. This increases setup time
|
||||
# to an entire cycle, and doesn't add latency.
|
||||
io_args.append(("i", "D_OUT_0", pin.o0[bit]))
|
||||
io_args.append(("i", "D_OUT_1", o1_ff))
|
||||
|
||||
if pin.dir in ("oe", "io"):
|
||||
io_args.append(("i", "OUTPUT_ENABLE", pin.oe))
|
||||
|
||||
m.submodules += Instance("SB_IO", *io_args)
|
||||
|
||||
return m
|
||||
|
||||
def get_input(self, pin, port, extras):
|
||||
self._check_feature("single-ended input", pin, extras,
|
||||
valid_xdrs=(0,), valid_extras=True)
|
||||
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]),
|
||||
])
|
||||
valid_xdrs=(0, 1, 2), valid_extras=True)
|
||||
return self._get_io_buffer(pin, port, extras)
|
||||
|
||||
def get_output(self, pin, port, extras):
|
||||
self._check_feature("single-ended output", pin, extras,
|
||||
valid_xdrs=(0,), valid_extras=True)
|
||||
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]),
|
||||
])
|
||||
valid_xdrs=(0, 1, 2), valid_extras=True)
|
||||
return self._get_io_buffer(pin, port, extras)
|
||||
|
||||
def get_tristate(self, pin, port, extras):
|
||||
self._check_feature("single-ended tristate", pin, extras,
|
||||
valid_xdrs=(0,), valid_extras=True)
|
||||
return self._get_io_buffer(port, extras, lambda bit: [
|
||||
# PIN_OUTPUT_TRISTATE|PIN_INPUT_REGISTERED
|
||||
("p", "PIN_TYPE", 0b1010_00),
|
||||
("i", "D_OUT_0", pin.o[bit]),
|
||||
("i", "OUTPUT_ENABLE", pin.oe),
|
||||
])
|
||||
valid_xdrs=(0, 1, 2), valid_extras=True)
|
||||
return self._get_io_buffer(pin, port, extras)
|
||||
|
||||
def get_input_output(self, pin, port, extras):
|
||||
self._check_feature("single-ended input/output", pin, extras,
|
||||
valid_xdrs=(0,), valid_extras=True)
|
||||
return self._get_io_buffer(port, extras, lambda bit: [
|
||||
# PIN_OUTPUT_TRISTATE|PIN_INPUT
|
||||
("p", "PIN_TYPE", 0b1010_01),
|
||||
("o", "D_IN_0", pin.i[bit]),
|
||||
("i", "D_OUT_0", pin.o[bit]),
|
||||
("i", "OUTPUT_ENABLE", pin.oe),
|
||||
])
|
||||
valid_xdrs=(0, 1, 2), valid_extras=True)
|
||||
return self._get_io_buffer(pin, port, extras)
|
||||
|
||||
|
||||
class IceStormProgrammerMixin:
|
||||
|
|
Loading…
Reference in a new issue