From: William D. Jones Date: Sun, 7 Jul 2019 20:44:48 +0000 (-0400) Subject: vendor.xilinx_spartan_3_6: Add Spartan3A family support. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=63da33dd7992a1af809705bcf319ae0d4877edf1;p=nmigen.git vendor.xilinx_spartan_3_6: Add Spartan3A family support. --- diff --git a/nmigen/vendor/xilinx_spartan6.py b/nmigen/vendor/xilinx_spartan6.py deleted file mode 100644 index 8ba4981..0000000 --- a/nmigen/vendor/xilinx_spartan6.py +++ /dev/null @@ -1,355 +0,0 @@ -from abc import abstractproperty - -from ..hdl.ast import * -from ..hdl.dsl import * -from ..hdl.ir import * -from ..build import * - - -__all__ = ["XilinxSpartan6Platform"] - - -class XilinxSpartan6Platform(TemplatedPlatform): - """ - Required tools: - * ISE toolchain: - * ``xst`` - * ``ngdbuild`` - * ``map`` - * ``par`` - * ``bitgen`` - - The environment is populated by running the script specified in the environment variable - ``NMIGEN_ISE_env``, if present. - - Available overrides: - * ``script_after_run``: inserts commands after ``run`` in XST script. - * ``add_constraints``: inserts commands in UCF file. - * ``xst_opts``: adds extra options for XST. - * ``ngdbuild_opts``: adds extra options for NGDBuild. - * ``map_opts``: adds extra options for MAP. - * ``par_opts``: adds extra options for PAR. - * ``bitgen_opts``: adds extra options for BitGen. - - Build products: - * ``{{name}}.srp``: synthesis report. - * ``{{name}}.ngc``: synthesized RTL. - * ``{{name}}.bld``: NGDBuild log. - * ``{{name}}.ngd``: design database. - * ``{{name}}_map.map``: MAP log. - * ``{{name}}_map.mrp``: mapping report. - * ``{{name}}_map.ncd``: mapped netlist. - * ``{{name}}.pcf``: physical constraints. - * ``{{name}}_par.par``: PAR log. - * ``{{name}}_par_pad.txt``: I/O usage report. - * ``{{name}}_par.ncd``: place and routed netlist. - * ``{{name}}.drc``: DRC report. - * ``{{name}}.bgn``: BitGen log. - * ``{{name}}.bit``: binary bitstream. - """ - - toolchain = "ISE" - - device = abstractproperty() - package = abstractproperty() - speed = abstractproperty() - - file_templates = { - **TemplatedPlatform.build_script_templates, - "{{name}}.v": r""" - /* {{autogenerated}} */ - {{emit_design("verilog")}} - """, - "{{name}}.prj": r""" - # {{autogenerated}} - {% for file in platform.iter_extra_files(".vhd", ".vhdl") -%} - vhdl work {{file}} - {% endfor %} - {% for file in platform.iter_extra_files(".v") -%} - verilog work {{file}} - {% endfor %} - verilog work {{name}}.v - """, - "{{name}}.xst": r""" - # {{autogenerated}} - run - -ifn {{name}}.prj - -ofn {{name}}.ngc - -top {{name}} - -p {{platform.device}}{{platform.package}}-{{platform.speed}} - {{get_override("script_after_run")|default("# (script_after_run placeholder)")}} - """, - "{{name}}.ucf": r""" - # {{autogenerated}} - {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%} - {% set port_name = port_name|replace("[", "<")|replace("]", ">") -%} - NET "{{port_name}}" LOC={{pin_name}}; - {% for attr_name, attr_value in attrs.items() -%} - NET "{{port_name}}" {{attr_name}}={{attr_value}}; - {% endfor %} - {% endfor %} - {% for signal, frequency in platform.iter_clock_constraints() -%} - NET "{{signal.name}}" TNM_NET="PRD{{signal.name}}"; - TIMESPEC "TS{{signal.name}}"=PERIOD "PRD{{signal.name}}" {{1000000000/frequency}} ns HIGH 50%; - {% endfor %} - {{get_override("add_constraints")|default("# (add_constraints placeholder)")}} - """ - } - command_templates = [ - r""" - {{get_tool("xst")}} - {{get_override("xst_opts")|options}} - -ifn {{name}}.xst - """, - r""" - {{get_tool("ngdbuild")}} - {{quiet("-quiet")}} - {{verbose("-verbose")}} - {{get_override("ngdbuild_opts")|options}} - -uc {{name}}.ucf - {{name}}.ngc - """, - r""" - {{get_tool("map")}} - {{verbose("-detail")}} - {{get_override("map_opts")|default(["-w"])|options}} - -o {{name}}_map.ncd - {{name}}.ngd - {{name}}.pcf - """, - r""" - {{get_tool("par")}} - {{get_override("par_opts")|default(["-w"])|options}} - {{name}}_map.ncd - {{name}}_par.ncd - {{name}}.pcf - """, - r""" - {{get_tool("bitgen")}} - {{get_override("bitgen_opts")|default(["-w"])|options}} - {{name}}_par.ncd - {{name}}.bit - """ - ] - - def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None): - def get_dff(clk, d, q): - # SDR I/O is performed by packing a flip-flop into the pad IOB. - for bit in range(len(q)): - _q = Signal() - _q.attrs["IOB"] = "TRUE" - m.submodules += Instance("FDCE", - i_C=clk, - i_CE=Const(1), - i_CLR=Const(0), - i_D=d[bit], - o_Q=_q, - ) - m.d.comb += q[bit].eq(_q) - - def get_iddr(clk, d, q0, q1): - for bit in range(len(q0)): - m.submodules += Instance("IDDR2", - p_DDR_ALIGNMENT="C0", - p_SRTYPE="ASYNC", - p_INIT_Q0=0, p_INIT_Q1=0, - i_C0=clk, i_C1=~clk, - i_CE=Const(1), - i_S=Const(0), i_R=Const(0), - i_D=d[bit], - o_Q0=q0[bit], o_Q1=q1[bit] - ) - - def get_oddr(clk, d0, d1, q): - for bit in range(len(q)): - m.submodules += Instance("ODDR2", - p_DDR_ALIGNMENT="C0", - p_SRTYPE="ASYNC", - p_INIT=0, - i_C0=clk, i_C1=~clk, - i_CE=Const(1), - i_S=Const(0), i_R=Const(0), - i_D0=d0[bit], i_D1=d1[bit], - o_Q=q[bit] - ) - - def get_ixor(y, invert): - if invert is None: - return y - else: - a = Signal.like(y, name_suffix="_x{}".format(1 if invert else 0)) - for bit in range(len(y)): - m.submodules += Instance("LUT1", - p_INIT=0b01 if invert else 0b10, - i_I0=a[bit], - o_O=y[bit] - ) - return a - - def get_oxor(a, invert): - if invert is None: - return a - else: - y = Signal.like(a, name_suffix="_x{}".format(1 if invert else 0)) - for bit in range(len(a)): - m.submodules += Instance("LUT1", - p_INIT=0b01 if invert else 0b10, - i_I0=a[bit], - o_O=y[bit] - ) - return y - - if "i" in pin.dir: - if pin.xdr < 2: - pin_i = get_ixor(pin.i, i_invert) - elif pin.xdr == 2: - pin_i0 = get_ixor(pin.i0, i_invert) - pin_i1 = get_ixor(pin.i1, i_invert) - if "o" in pin.dir: - if pin.xdr < 2: - pin_o = get_oxor(pin.o, o_invert) - elif pin.xdr == 2: - pin_o0 = get_oxor(pin.o0, o_invert) - pin_o1 = get_oxor(pin.o1, o_invert) - - i = o = t = None - if "i" in pin.dir: - i = Signal(pin.width, name="{}_xdr_i".format(pin.name)) - if "o" in pin.dir: - o = Signal(pin.width, name="{}_xdr_o".format(pin.name)) - if pin.dir in ("oe", "io"): - t = Signal(1, name="{}_xdr_t".format(pin.name)) - - if pin.xdr == 0: - if "i" in pin.dir: - i = pin_i - if "o" in pin.dir: - o = pin_o - if pin.dir in ("oe", "io"): - t = ~pin.oe - elif pin.xdr == 1: - if "i" in pin.dir: - get_dff(pin.i_clk, i, pin_i) - if "o" in pin.dir: - get_dff(pin.o_clk, pin_o, o) - if pin.dir in ("oe", "io"): - get_dff(pin.o_clk, ~pin.oe, t) - elif pin.xdr == 2: - if "i" in pin.dir: - # Re-register first input before it enters fabric. This allows both inputs to - # enter fabric on the same clock edge, and adds one cycle of latency. - i0_ff = Signal.like(pin_i0, name_suffix="_ff") - get_dff(pin.i_clk, i0_ff, pin_i0) - get_iddr(pin.i_clk, i, i0_ff, pin_i1) - if "o" in pin.dir: - get_oddr(pin.o_clk, pin_o0, pin_o1, o) - if pin.dir in ("oe", "io"): - get_dff(pin.o_clk, ~pin.oe, t) - else: - assert False - - return (i, o, t) - - def get_input(self, pin, port, attrs, invert): - self._check_feature("single-ended input", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None) - for bit in range(len(port)): - m.submodules[pin.name] = Instance("IBUF", - i_I=port[bit], - o_O=i[bit] - ) - return m - - def get_output(self, pin, port, attrs, invert): - self._check_feature("single-ended output", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) - for bit in range(len(port)): - m.submodules[pin.name] = Instance("OBUF", - i_I=o[bit], - o_O=port[bit] - ) - return m - - def get_tristate(self, pin, port, attrs, invert): - self._check_feature("single-ended tristate", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) - for bit in range(len(port)): - m.submodules[pin.name] = Instance("OBUFT", - i_T=t, - i_I=o[bit], - o_O=port[bit] - ) - return m - - def get_input_output(self, pin, port, attrs, invert): - self._check_feature("single-ended input/output", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None, - o_invert=True if invert else None) - for bit in range(len(port)): - m.submodules[pin.name] = Instance("IOBUF", - i_T=t, - i_I=o[bit], - o_O=i[bit], - io_IO=port[bit] - ) - return m - - def get_diff_input(self, pin, p_port, n_port, attrs, invert): - self._check_feature("differential input", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None) - for bit in range(len(p_port)): - m.submodules[pin.name] = Instance("IBUFDS", - i_I=p_port[bit], i_IB=n_port[bit], - o_O=i[bit] - ) - return m - - def get_diff_output(self, pin, p_port, n_port, attrs, invert): - self._check_feature("differential output", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) - for bit in range(len(p_port)): - m.submodules[pin.name] = Instance("OBUFDS", - i_I=o[bit], - o_O=p_port[bit], o_OB=n_port[bit] - ) - return m - - def get_diff_tristate(self, pin, p_port, n_port, attrs, invert): - self._check_feature("differential tristate", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) - for bit in range(len(p_port)): - m.submodules[pin.name] = Instance("OBUFTDS", - i_T=t, - i_I=o[bit], - o_O=p_port[bit], o_OB=n_port[bit] - ) - return m - - def get_diff_input_output(self, pin, p_port, n_port, attrs, invert): - self._check_feature("differential input/output", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) - m = Module() - i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None, - o_invert=True if invert else None) - for bit in range(len(p_port)): - m.submodules[pin.name] = Instance("IOBUFDS", - i_T=t, - i_I=o[bit], - o_O=i[bit], - io_IO=p_port[bit], io_IOB=n_port[bit] - ) - return m diff --git a/nmigen/vendor/xilinx_spartan_3_6.py b/nmigen/vendor/xilinx_spartan_3_6.py new file mode 100644 index 0000000..74a9645 --- /dev/null +++ b/nmigen/vendor/xilinx_spartan_3_6.py @@ -0,0 +1,386 @@ +from abc import abstractproperty + +from ..hdl.ast import * +from ..hdl.dsl import * +from ..hdl.ir import * +from ..build import * + + +__all__ = ["XilinxSpartan3APlatform", "XilinxSpartan6Platform"] + +# The interface to Spartan 3 and 6 are substantially the same. Handle +# differences internally using one class and expose user-aliases for +# convenience. + + +class XilinxSpartan3Or6Platform(TemplatedPlatform): + """ + Required tools: + * ISE toolchain: + * ``xst`` + * ``ngdbuild`` + * ``map`` + * ``par`` + * ``bitgen`` + + The environment is populated by running the script specified in the environment variable + ``NMIGEN_ISE_env``, if present. + + Available overrides: + * ``script_after_run``: inserts commands after ``run`` in XST script. + * ``add_constraints``: inserts commands in UCF file. + * ``xst_opts``: adds extra options for XST. + * ``ngdbuild_opts``: adds extra options for NGDBuild. + * ``map_opts``: adds extra options for MAP. + * ``par_opts``: adds extra options for PAR. + * ``bitgen_opts``: adds extra options for BitGen. + + Build products: + * ``{{name}}.srp``: synthesis report. + * ``{{name}}.ngc``: synthesized RTL. + * ``{{name}}.bld``: NGDBuild log. + * ``{{name}}.ngd``: design database. + * ``{{name}}_map.map``: MAP log. + * ``{{name}}_map.mrp``: mapping report. + * ``{{name}}_map.ncd``: mapped netlist. + * ``{{name}}.pcf``: physical constraints. + * ``{{name}}_par.par``: PAR log. + * ``{{name}}_par_pad.txt``: I/O usage report. + * ``{{name}}_par.ncd``: place and routed netlist. + * ``{{name}}.drc``: DRC report. + * ``{{name}}.bgn``: BitGen log. + * ``{{name}}.bit``: binary bitstream with metadata. + * ``{{name}}.bin``: raw binary bitstream. + """ + + toolchain = "ISE" + + device = abstractproperty() + package = abstractproperty() + speed = abstractproperty() + + file_templates = { + **TemplatedPlatform.build_script_templates, + "{{name}}.v": r""" + /* {{autogenerated}} */ + {{emit_design("verilog")}} + """, + "{{name}}.prj": r""" + # {{autogenerated}} + {% for file in platform.iter_extra_files(".vhd", ".vhdl") -%} + vhdl work {{file}} + {% endfor %} + {% for file in platform.iter_extra_files(".v") -%} + verilog work {{file}} + {% endfor %} + verilog work {{name}}.v + """, + "{{name}}.xst": r""" + # {{autogenerated}} + run + -ifn {{name}}.prj + -ofn {{name}}.ngc + -top {{name}} + {% if platform.family in ["3", "3E", "3A"] %} + -use_new_parser yes + {% endif %} + -register_balancing yes + -p {{platform.device}}{{platform.package}}-{{platform.speed}} + {{get_override("script_after_run")|default("# (script_after_run placeholder)")}} + """, + "{{name}}.ucf": r""" + # {{autogenerated}} + {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%} + {% set port_name = port_name|replace("[", "<")|replace("]", ">") -%} + NET "{{port_name}}" LOC={{pin_name}}; + {% for attr_name, attr_value in attrs.items() -%} + NET "{{port_name}}" {{attr_name}}={{attr_value}}; + {% endfor %} + {% endfor %} + {% for signal, frequency in platform.iter_clock_constraints() -%} + NET "{{signal.name}}" TNM_NET="PRD{{signal.name}}"; + TIMESPEC "TS{{signal.name}}"=PERIOD "PRD{{signal.name}}" {{1000000000/frequency}} ns HIGH 50%; + {% endfor %} + {{get_override("add_constraints")|default("# (add_constraints placeholder)")}} + """ + } + command_templates = [ + r""" + {{get_tool("xst")}} + {{get_override("xst_opts")|options}} + -ifn {{name}}.xst + """, + r""" + {{get_tool("ngdbuild")}} + {{quiet("-quiet")}} + {{verbose("-verbose")}} + {{get_override("ngdbuild_opts")|options}} + -uc {{name}}.ucf + {{name}}.ngc + """, + r""" + {{get_tool("map")}} + {{verbose("-detail")}} + {{get_override("map_opts")|default(["-w"])|options}} + -o {{name}}_map.ncd + {{name}}.ngd + {{name}}.pcf + """, + r""" + {{get_tool("par")}} + {{get_override("par_opts")|default(["-w"])|options}} + {{name}}_map.ncd + {{name}}_par.ncd + {{name}}.pcf + """, + r""" + {{get_tool("bitgen")}} + {{get_override("bitgen_opts")|default(["-w"])|options}} + -g Binary:Yes + {{name}}_par.ncd + {{name}}.bit + """ + ] + + @property + def family(self): + device = self.device.upper() + if device.startswith("XC3S"): + if device.endswith("A"): + return "3A" + elif device.endswith("E"): + raise NotImplementedError("""Spartan 3E family is not supported + as a nMigen platform.""") + else: + raise NotImplementedError("""Spartan 3 family is not supported + as a nMigen platform.""") + elif device.startswith("XC6S"): + return "6" + else: + assert False + + def _get_xdr_buffer(self, m, pin, i_invert=None, o_invert=None): + def get_dff(clk, d, q): + # SDR I/O is performed by packing a flip-flop into the pad IOB. + for bit in range(len(q)): + _q = Signal() + _q.attrs["IOB"] = "TRUE" + m.submodules += Instance("FDCE", + i_C=clk, + i_CE=Const(1), + i_CLR=Const(0), + i_D=d[bit], + o_Q=_q, + ) + m.d.comb += q[bit].eq(_q) + + def get_iddr(clk, d, q0, q1): + for bit in range(len(q0)): + m.submodules += Instance("IDDR2", + p_DDR_ALIGNMENT="C0", + p_SRTYPE="ASYNC", + p_INIT_Q0=0, p_INIT_Q1=0, + i_C0=clk, i_C1=~clk, + i_CE=Const(1), + i_S=Const(0), i_R=Const(0), + i_D=d[bit], + o_Q0=q0[bit], o_Q1=q1[bit] + ) + + def get_oddr(clk, d0, d1, q): + for bit in range(len(q)): + m.submodules += Instance("ODDR2", + p_DDR_ALIGNMENT="C0", + p_SRTYPE="ASYNC", + p_INIT=0, + i_C0=clk, i_C1=~clk, + i_CE=Const(1), + i_S=Const(0), i_R=Const(0), + i_D0=d0[bit], i_D1=d1[bit], + o_Q=q[bit] + ) + + def get_ixor(y, invert): + if invert is None: + return y + else: + a = Signal.like(y, name_suffix="_x{}".format(1 if invert else 0)) + for bit in range(len(y)): + m.submodules += Instance("LUT1", + p_INIT=0b01 if invert else 0b10, + i_I0=a[bit], + o_O=y[bit] + ) + return a + + def get_oxor(a, invert): + if invert is None: + return a + else: + y = Signal.like(a, name_suffix="_x{}".format(1 if invert else 0)) + for bit in range(len(a)): + m.submodules += Instance("LUT1", + p_INIT=0b01 if invert else 0b10, + i_I0=a[bit], + o_O=y[bit] + ) + return y + + if "i" in pin.dir: + if pin.xdr < 2: + pin_i = get_ixor(pin.i, i_invert) + elif pin.xdr == 2: + pin_i0 = get_ixor(pin.i0, i_invert) + pin_i1 = get_ixor(pin.i1, i_invert) + if "o" in pin.dir: + if pin.xdr < 2: + pin_o = get_oxor(pin.o, o_invert) + elif pin.xdr == 2: + pin_o0 = get_oxor(pin.o0, o_invert) + pin_o1 = get_oxor(pin.o1, o_invert) + + i = o = t = None + if "i" in pin.dir: + i = Signal(pin.width, name="{}_xdr_i".format(pin.name)) + if "o" in pin.dir: + o = Signal(pin.width, name="{}_xdr_o".format(pin.name)) + if pin.dir in ("oe", "io"): + t = Signal(1, name="{}_xdr_t".format(pin.name)) + + if pin.xdr == 0: + if "i" in pin.dir: + i = pin_i + if "o" in pin.dir: + o = pin_o + if pin.dir in ("oe", "io"): + t = ~pin.oe + elif pin.xdr == 1: + if "i" in pin.dir: + get_dff(pin.i_clk, i, pin_i) + if "o" in pin.dir: + get_dff(pin.o_clk, pin_o, o) + if pin.dir in ("oe", "io"): + get_dff(pin.o_clk, ~pin.oe, t) + elif pin.xdr == 2: + if "i" in pin.dir: + # Re-register first input before it enters fabric. This allows both inputs to + # enter fabric on the same clock edge, and adds one cycle of latency. + i0_ff = Signal.like(pin_i0, name_suffix="_ff") + get_dff(pin.i_clk, i0_ff, pin_i0) + get_iddr(pin.i_clk, i, i0_ff, pin_i1) + if "o" in pin.dir: + get_oddr(pin.o_clk, pin_o0, pin_o1, o) + if pin.dir in ("oe", "io"): + get_dff(pin.o_clk, ~pin.oe, t) + else: + assert False + + return (i, o, t) + + def get_input(self, pin, port, attrs, invert): + self._check_feature("single-ended input", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None) + for bit in range(len(port)): + m.submodules[pin.name] = Instance("IBUF", + i_I=port[bit], + o_O=i[bit] + ) + return m + + def get_output(self, pin, port, attrs, invert): + self._check_feature("single-ended output", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) + for bit in range(len(port)): + m.submodules[pin.name] = Instance("OBUF", + i_I=o[bit], + o_O=port[bit] + ) + return m + + def get_tristate(self, pin, port, attrs, invert): + self._check_feature("single-ended tristate", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) + for bit in range(len(port)): + m.submodules[pin.name] = Instance("OBUFT", + i_T=t, + i_I=o[bit], + o_O=port[bit] + ) + return m + + def get_input_output(self, pin, port, attrs, invert): + self._check_feature("single-ended input/output", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None, + o_invert=True if invert else None) + for bit in range(len(port)): + m.submodules[pin.name] = Instance("IOBUF", + i_T=t, + i_I=o[bit], + o_O=i[bit], + io_IO=port[bit] + ) + return m + + def get_diff_input(self, pin, p_port, n_port, attrs, invert): + self._check_feature("differential input", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None) + for bit in range(len(p_port)): + m.submodules[pin.name] = Instance("IBUFDS", + i_I=p_port[bit], i_IB=n_port[bit], + o_O=i[bit] + ) + return m + + def get_diff_output(self, pin, p_port, n_port, attrs, invert): + self._check_feature("differential output", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) + for bit in range(len(p_port)): + m.submodules[pin.name] = Instance("OBUFDS", + i_I=o[bit], + o_O=p_port[bit], o_OB=n_port[bit] + ) + return m + + def get_diff_tristate(self, pin, p_port, n_port, attrs, invert): + self._check_feature("differential tristate", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, o_invert=True if invert else None) + for bit in range(len(p_port)): + m.submodules[pin.name] = Instance("OBUFTDS", + i_T=t, + i_I=o[bit], + o_O=p_port[bit], o_OB=n_port[bit] + ) + return m + + def get_diff_input_output(self, pin, p_port, n_port, attrs, invert): + self._check_feature("differential input/output", pin, attrs, + valid_xdrs=(0, 1, 2), valid_attrs=True) + m = Module() + i, o, t = self._get_xdr_buffer(m, pin, i_invert=True if invert else None, + o_invert=True if invert else None) + for bit in range(len(p_port)): + m.submodules[pin.name] = Instance("IOBUFDS", + i_T=t, + i_I=o[bit], + o_O=i[bit], + io_IO=p_port[bit], io_IOB=n_port[bit] + ) + return m + + +XilinxSpartan3APlatform = XilinxSpartan3Or6Platform +XilinxSpartan6Platform = XilinxSpartan3Or6Platform