class Xilinx7SeriesPlatform(TemplatedPlatform):
"""
+ Vivado toolchain
+ ----------------
+
Required tools:
* ``vivado``
* ``{{name}}_route.dcp``: Vivado design checkpoint.
* ``{{name}}.bit``: binary bitstream with metadata.
* ``{{name}}.bin``: binary bitstream.
+
+ Symbiflow toolchain
+ -------------------
+
+ Required tools:
+ * ``synth``
+ * ``pack``
+ * ``place``
+ * ``route``
+ * ``write_fasm``
+ * ``write_bitstream``
+
+ The environment is populated by running the script specified in the environment variable
+ ``NMIGEN_ENV_Symbiflow``, if present.
+
+ Available overrides:
+ * ``add_constraints``: inserts commands in XDC file.
"""
- toolchain = "Vivado"
+ toolchain = None # selected when creating platform
device = abstractproperty()
package = abstractproperty()
def _part(self):
return "{}{}-{}".format(self.device, self.package, self.speed)
- required_tools = ["vivado"]
- file_templates = {
+ # Vivado templates
+
+ _vivado_required_tools = ["vivado"]
+ _vivado_file_templates = {
**TemplatedPlatform.build_script_templates,
"build_{{name}}.sh": r"""
# {{autogenerated}}
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
"""
}
- command_templates = [
+ _vivado_command_templates = [
r"""
{{invoke_tool("vivado")}}
{{verbose("-verbose")}}
"""
]
+ # Symbiflow templates
+
+ _symbiflow_part_map = {
+ "xc7a35ticsg324-1L": "xc7a35tcsg324-1", # Arty-A7
+ }
+
+ _symbiflow_required_tools = [
+ "synth",
+ "pack",
+ "place",
+ "route",
+ "write_fasm",
+ "write_bitstream"
+ ]
+ _symbiflow_file_templates = {
+ **TemplatedPlatform.build_script_templates,
+ "{{name}}.v": r"""
+ /* {{autogenerated}} */
+ {{emit_verilog()}}
+ """,
+ "{{name}}.debug.v": r"""
+ /* {{autogenerated}} */
+ {{emit_debug_verilog()}}
+ """,
+ "{{name}}.pcf": r"""
+ # {{autogenerated}}
+ {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
+ set_io {{port_name}} {{pin_name}}
+ {% endfor %}
+ """,
+ "{{name}}.xdc": r"""
+ # {{autogenerated}}
+ {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
+ {% for attr_name, attr_value in attrs.items() -%}
+ set_property {{attr_name}} {{attr_value}} [get_ports {{port_name|tcl_escape}} }]
+ {% endfor %}
+ {% endfor %}
+ {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
+ """,
+ "{{name}}.sdc": r"""
+ # {{autogenerated}}
+ {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
+ {% if port_signal is none -%}
+ create_clock -period {{1000000000/frequency}} {{net_signal.name|ascii_escape}}
+ {% endif %}
+ {% endfor %}
+ """
+ }
+ _symbiflow_command_templates = [
+ r"""
+ {{invoke_tool("synth")}}
+ -t {{name}}
+ -v {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%} {{file}} {% endfor %} {{name}}.v
+ -p {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
+ -x {{name}}.xdc
+ """,
+ r"""
+ {{invoke_tool("pack")}}
+ -e {{name}}.eblif
+ -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
+ -s {{name}}.sdc
+ """,
+ r"""
+ {{invoke_tool("place")}}
+ -e {{name}}.eblif
+ -p {{name}}.pcf
+ -n {{name}}.net
+ -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
+ -s {{name}}.sdc
+ """,
+ r"""
+ {{invoke_tool("route")}}
+ -e {{name}}.eblif
+ -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
+ -s {{name}}.sdc
+ """,
+ r"""
+ {{invoke_tool("write_fasm")}}
+ -e {{name}}.eblif
+ -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
+ """,
+ r"""
+ {{invoke_tool("write_bitstream")}}
+ -f {{name}}.fasm
+ -p {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
+ -b {{name}}.bit
+ """
+ ]
+
+ # Common logic
+
+ def __init__(self, *, toolchain="Vivado"):
+ super().__init__()
+
+ assert toolchain in ("Vivado", "Symbiflow")
+ self.toolchain = toolchain
+
+ @property
+ def required_tools(self):
+ if self.toolchain == "Vivado":
+ return self._vivado_required_tools
+ if self.toolchain == "Symbiflow":
+ return self._symbiflow_required_tools
+ assert False
+
+ @property
+ def file_templates(self):
+ if self.toolchain == "Vivado":
+ return self._vivado_file_templates
+ if self.toolchain == "Symbiflow":
+ return self._symbiflow_file_templates
+ assert False
+
+ @property
+ def command_templates(self):
+ if self.toolchain == "Vivado":
+ return self._vivado_command_templates
+ if self.toolchain == "Symbiflow":
+ return self._symbiflow_command_templates
+ assert False
+
def create_missing_domain(self, name):
# Xilinx devices have a global write enable (GWE) signal that asserted during configuraiton
# and deasserted once it ends. Because it is an asynchronous signal (GWE is driven by logic
rst_i = self.request(self.default_rst).i
m = Module()
- ready = Signal()
- m.submodules += Instance("STARTUPE2", o_EOS=ready)
- m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
- # Actually use BUFGCTRL configured as BUFGCE, since using BUFGCE causes sim/synth
- # mismatches with Vivado 2019.2, and the suggested workaround (SIM_DEVICE parameter)
- # breaks Vivado 2017.4.
- m.submodules += Instance("BUFGCTRL",
- i_I0=clk_i, i_S0=C(1, 1), i_CE0=ready, i_IGNORE0=C(0, 1),
- i_I1=C(1, 1), i_S1=C(0, 1), i_CE1=C(0, 1), i_IGNORE1=C(1, 1),
- o_O=ClockSignal("sync")
- )
+
+ if self.toolchain == "Vivado":
+ ready = Signal()
+ m.submodules += Instance("STARTUPE2", o_EOS=ready)
+ m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
+ # Actually use BUFGCTRL configured as BUFGCE, since using BUFGCE causes sim/synth
+ # mismatches with Vivado 2019.2, and the suggested workaround (SIM_DEVICE parameter)
+ # breaks Vivado 2017.4.
+ m.submodules += Instance("BUFGCTRL",
+ i_I0=clk_i, i_S0=C(1, 1), i_CE0=ready, i_IGNORE0=C(0, 1),
+ i_I1=C(1, 1), i_S1=C(0, 1), i_CE1=C(0, 1), i_IGNORE1=C(1, 1),
+ o_O=ClockSignal("sync")
+ )
+ elif self.toolchain == "Symbiflow":
+ cd_sync = ClockDomain("sync", reset_less=self.default_rst is None)
+ m.domains += cd_sync
+ m.submodules += Instance("BUFG", i_I=clk_i, o_O=cd_sync.clk)
+ self.add_clock_constraint(cd_sync.clk, self.default_clk_frequency)
+ else:
+ assert False
+
if self.default_rst is not None:
m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
return m
valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module()
i, o, t = self._get_xdr_buffer(m, pin, o_invert=invert)
- for bit in range(pin.width):
- m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUF",
- i_I=o[bit],
- o_O=port.io[bit]
- )
+ if self.toolchain == "Vivado":
+ for bit in range(pin.width):
+ m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUF",
+ i_I=o[bit],
+ o_O=port.io[bit]
+ )
+ elif self.toolchain == "Symbiflow":
+ m.d.comb += port.eq(self._invert_if(invert, o))
+ else:
+ assert False
return m
def get_tristate(self, pin, port, attrs, invert):
+ if toolchain == "Symbiflow":
+ return super().get_tristate(pin, port, attrs, invert)
+
self._check_feature("single-ended tristate", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module()
return m
def get_input_output(self, pin, port, attrs, invert):
+ if toolchain == "Symbiflow":
+ return super().get_input_output(pin, port, attrs, invert)
+
self._check_feature("single-ended input/output", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module()
return m
def get_diff_input(self, pin, port, attrs, invert):
+ if toolchain == "Symbiflow":
+ return super().get_diff_input(pin, port, attrs, invert)
+
self._check_feature("differential input", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module()
return m
def get_diff_output(self, pin, port, attrs, invert):
+ if toolchain == "Symbiflow":
+ return super().get_diff_output(pin, port, attrs, invert)
+
self._check_feature("differential output", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module()
return m
def get_diff_tristate(self, pin, port, attrs, invert):
+ if toolchain == "Symbiflow":
+ return super().get_diff_tristate(pin, port, attrs, invert)
+
self._check_feature("differential tristate", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module()
return m
def get_diff_input_output(self, pin, port, attrs, invert):
+ if toolchain == "Symbiflow":
+ return super().get_diff_input_output(pin, port, attrs, invert)
+
self._check_feature("differential input/output", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module()