vendor: Add initial support for Symbiflow for Xilinx 7-series
This commit is contained in:
parent
77616837e8
commit
4e208b0ac1
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue