"""
]
- 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: