vendor.fpga.lattice_ice40: implement SDR and DDR I/O buffers.

This commit is contained in:
whitequark 2019-06-03 07:43:02 +00:00
parent b42043f764
commit 185abb492d

View file

@ -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() 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)): for bit in range(len(port)):
m.submodules += Instance("SB_IO", io_args = [
("io", "PACKAGE_PIN", port[bit]), ("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 return m
def get_input(self, pin, port, extras): def get_input(self, pin, port, extras):
self._check_feature("single-ended input", pin, extras, self._check_feature("single-ended input", pin, extras,
valid_xdrs=(0,), valid_extras=True) valid_xdrs=(0, 1, 2), valid_extras=True)
return self._get_io_buffer(port, extras, lambda bit: [ return self._get_io_buffer(pin, port, extras)
# PIN_NO_OUTPUT|PIN_INPUT
("p", "PIN_TYPE", 0b0000_01),
("o", "D_IN_0", pin.i[bit]),
])
def get_output(self, pin, port, extras): def get_output(self, pin, port, extras):
self._check_feature("single-ended output", pin, extras, self._check_feature("single-ended output", pin, extras,
valid_xdrs=(0,), valid_extras=True) valid_xdrs=(0, 1, 2), valid_extras=True)
return self._get_io_buffer(port, extras, lambda bit: [ return self._get_io_buffer(pin, port, extras)
# PIN_OUTPUT|PIN_INPUT_REGISTERED
("p", "PIN_TYPE", 0b0110_00),
("i", "D_OUT_0", pin.o[bit]),
])
def get_tristate(self, pin, port, extras): def get_tristate(self, pin, port, extras):
self._check_feature("single-ended tristate", pin, extras, self._check_feature("single-ended tristate", pin, extras,
valid_xdrs=(0,), valid_extras=True) valid_xdrs=(0, 1, 2), valid_extras=True)
return self._get_io_buffer(port, extras, lambda bit: [ return self._get_io_buffer(pin, port, extras)
# PIN_OUTPUT_TRISTATE|PIN_INPUT_REGISTERED
("p", "PIN_TYPE", 0b1010_00),
("i", "D_OUT_0", pin.o[bit]),
("i", "OUTPUT_ENABLE", pin.oe),
])
def get_input_output(self, pin, port, extras): def get_input_output(self, pin, port, extras):
self._check_feature("single-ended input/output", pin, extras, self._check_feature("single-ended input/output", pin, extras,
valid_xdrs=(0,), valid_extras=True) valid_xdrs=(0, 1, 2), valid_extras=True)
return self._get_io_buffer(port, extras, lambda bit: [ return self._get_io_buffer(pin, port, extras)
# 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),
])
class IceStormProgrammerMixin: class IceStormProgrammerMixin: