vendor: Add initial support for Symbiflow for Xilinx 7-series

This commit is contained in:
Mariusz Glebocki 2020-08-02 18:48:26 +02:00 committed by whitequark
parent 77616837e8
commit 4e208b0ac1

View file

@ -10,6 +10,9 @@ __all__ = ["Xilinx7SeriesPlatform"]
class Xilinx7SeriesPlatform(TemplatedPlatform): class Xilinx7SeriesPlatform(TemplatedPlatform):
""" """
Vivado toolchain
----------------
Required tools: Required tools:
* ``vivado`` * ``vivado``
@ -44,9 +47,26 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
* ``{{name}}_route.dcp``: Vivado design checkpoint. * ``{{name}}_route.dcp``: Vivado design checkpoint.
* ``{{name}}.bit``: binary bitstream with metadata. * ``{{name}}.bit``: binary bitstream with metadata.
* ``{{name}}.bin``: binary bitstream. * ``{{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() device = abstractproperty()
package = abstractproperty() package = abstractproperty()
@ -56,8 +76,10 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
def _part(self): def _part(self):
return "{}{}-{}".format(self.device, self.package, self.speed) return "{}{}-{}".format(self.device, self.package, self.speed)
required_tools = ["vivado"] # Vivado templates
file_templates = {
_vivado_required_tools = ["vivado"]
_vivado_file_templates = {
**TemplatedPlatform.build_script_templates, **TemplatedPlatform.build_script_templates,
"build_{{name}}.sh": r""" "build_{{name}}.sh": r"""
# {{autogenerated}} # {{autogenerated}}
@ -143,7 +165,7 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}} {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
""" """
} }
command_templates = [ _vivado_command_templates = [
r""" r"""
{{invoke_tool("vivado")}} {{invoke_tool("vivado")}}
{{verbose("-verbose")}} {{verbose("-verbose")}}
@ -154,6 +176,127 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
""" """
] ]
# 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): def create_missing_domain(self, name):
# Xilinx devices have a global write enable (GWE) signal that asserted during configuraiton # 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 # and deasserted once it ends. Because it is an asynchronous signal (GWE is driven by logic
@ -169,17 +312,27 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
rst_i = self.request(self.default_rst).i rst_i = self.request(self.default_rst).i
m = Module() m = Module()
ready = Signal()
m.submodules += Instance("STARTUPE2", o_EOS=ready) if self.toolchain == "Vivado":
m.domains += ClockDomain("sync", reset_less=self.default_rst is None) ready = Signal()
# Actually use BUFGCTRL configured as BUFGCE, since using BUFGCE causes sim/synth m.submodules += Instance("STARTUPE2", o_EOS=ready)
# mismatches with Vivado 2019.2, and the suggested workaround (SIM_DEVICE parameter) m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
# breaks Vivado 2017.4. # Actually use BUFGCTRL configured as BUFGCE, since using BUFGCE causes sim/synth
m.submodules += Instance("BUFGCTRL", # mismatches with Vivado 2019.2, and the suggested workaround (SIM_DEVICE parameter)
i_I0=clk_i, i_S0=C(1, 1), i_CE0=ready, i_IGNORE0=C(0, 1), # breaks Vivado 2017.4.
i_I1=C(1, 1), i_S1=C(0, 1), i_CE1=C(0, 1), i_IGNORE1=C(1, 1), m.submodules += Instance("BUFGCTRL",
o_O=ClockSignal("sync") 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: if self.default_rst is not None:
m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync") m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
return m return m
@ -307,14 +460,22 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
valid_xdrs=(0, 1, 2), valid_attrs=True) valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module() m = Module()
i, o, t = self._get_xdr_buffer(m, pin, o_invert=invert) i, o, t = self._get_xdr_buffer(m, pin, o_invert=invert)
for bit in range(pin.width): if self.toolchain == "Vivado":
m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUF", for bit in range(pin.width):
i_I=o[bit], m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUF",
o_O=port.io[bit] 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 return m
def get_tristate(self, pin, port, attrs, invert): 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, self._check_feature("single-ended tristate", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True) valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module() m = Module()
@ -328,6 +489,9 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
return m return m
def get_input_output(self, pin, port, attrs, invert): 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, self._check_feature("single-ended input/output", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True) valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module() m = Module()
@ -342,6 +506,9 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
return m return m
def get_diff_input(self, pin, port, attrs, invert): 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, self._check_feature("differential input", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True) valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module() m = Module()
@ -354,6 +521,9 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
return m return m
def get_diff_output(self, pin, port, attrs, invert): 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, self._check_feature("differential output", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True) valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module() m = Module()
@ -366,6 +536,9 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
return m return m
def get_diff_tristate(self, pin, port, attrs, invert): 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, self._check_feature("differential tristate", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True) valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module() m = Module()
@ -379,6 +552,9 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
return m return m
def get_diff_input_output(self, pin, port, attrs, invert): 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, self._check_feature("differential input/output", pin, attrs,
valid_xdrs=(0, 1, 2), valid_attrs=True) valid_xdrs=(0, 1, 2), valid_attrs=True)
m = Module() m = Module()