vendor.xilinx: add support for Xray-based toolchain.

This commit is contained in:
Gwenhael Goavec-Merou 2022-12-13 21:09:57 +01:00 committed by GitHub
parent 0a1ba22050
commit e3b2ba4316
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -102,6 +102,17 @@ class XilinxPlatform(TemplatedPlatform):
Available overrides:
* ``add_constraints``: inserts commands in XDC file.
.. rubric:: Xray toolchain
Required tools:
* ``yosys``
* ``nextpnr-xilinx``
* ``fasm2frames``
* ``xc7frames2bit``
The environment is populated by running the script specified in the environment variable
``AMARANTH_ENV_Xray``, if present.
"""
toolchain = None # selected when creating platform
@ -117,6 +128,10 @@ class XilinxPlatform(TemplatedPlatform):
else:
return "{}{}-{}".format(self.device, self.package, self.speed)
@property
def vendor_toolchain(self):
return self.toolchain in ["Vivado", "ISE"]
# Vivado templates
_vivado_required_tools = ["vivado"]
@ -426,6 +441,93 @@ class XilinxPlatform(TemplatedPlatform):
"""
]
# Yosys NextPNR prjxray templates
@property
def _xray_part(self):
return {
"xc7a35ticsg324-1L": "xc7a35tcsg324-1", # Arty-A7 35t
"xc7a100ticsg324-1L": "xc7a100tcsg324-1", # Arty-A7 100t
}.get(self._part, self._part)
@property
def _xray_device(self):
return {
"xc7a35ti": "xc7a35t",
"xc7a100ti": "xc7a100t",
}.get(self.device, self.device)
@property
def _xray_family(self):
return {
"xc7a": "artix7",
"xc7z": "zynq7",
}[self.device[:4]]
_xray_required_tools = [
"yosys",
"nextpnr-xilinx",
"fasm2frames",
"xc7frames2bit"
]
_xray_file_templates = {
**TemplatedPlatform.build_script_templates,
"build_{{name}}.sh": r"""
# {{autogenerated}}
set -e{{verbose("x")}}
[ -n "${{platform._deprecated_toolchain_env_var}}" ] && . "${{platform._deprecated_toolchain_env_var}}"
[ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}"
: ${DB_DIR:=/usr/share/nextpnr/prjxray-db}
: ${CHIPDB_DIR:=/usr/share/nextpnr/xilinx-chipdb}
{{emit_commands("sh")}}
""",
"{{name}}.v": r"""
/* {{autogenerated}} */
{{emit_verilog()}}
""",
"{{name}}.debug.v": r"""
/* {{autogenerated}} */
{{emit_debug_verilog()}}
""",
"{{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}}]
set_property LOC {{pin_name}} [get_ports {{port_name|tcl_escape}}]
{% endfor %}
{% endfor %}
""",
}
_xray_command_templates = [
r"""
{{invoke_tool("yosys")}}
-p "synth_xilinx -flatten -abc9 -nobram -arch xc7 -top {{name}}; write_json {{name}}.json"
{% for file in platform.iter_files(".v", ".sv", ".vhd", ".vhdl") -%} {{file}} {% endfor %}
{{name}}.v
""",
r"""
{{invoke_tool("nextpnr-xilinx")}}
--chipdb $CHIPDB_DIR/{{platform._xray_device}}.bin
--xdc {{name}}.xdc
--json {{name}}.json
--write {{name}}_routed.json
--fasm {{name}}.fasm
""",
r"""
{{invoke_tool("fasm2frames")}}
--part {{platform._xray_part}}
--db-root $DB_DIR/{{platform._xray_family}} {{name}}.fasm > {{name}}.frames
""",
r"""
{{invoke_tool("xc7frames2bit")}}
--part_file $DB_DIR/{{platform._xray_family}}/{{platform._xray_part}}/part.yaml
--part_name {{platform._xray_part}}
--frm_file {{name}}.frames
--output_file {{name}}.bit
""",
]
# Common logic
def __init__(self, *, toolchain=None):
@ -499,7 +601,7 @@ class XilinxPlatform(TemplatedPlatform):
else:
toolchain = "Vivado"
assert toolchain in ("Vivado", "ISE", "Symbiflow")
assert toolchain in ("Vivado", "ISE", "Symbiflow", "Xray")
if toolchain == "Vivado":
if self.family in ISE_FAMILIES:
raise ValueError("Family '{}' is not supported by the Vivado toolchain, please use ISE instead".format(self.family))
@ -509,6 +611,10 @@ class XilinxPlatform(TemplatedPlatform):
elif toolchain == "Symbiflow":
if self.family != "series7":
raise ValueError("Family '{}' is not supported by the Symbiflow toolchain".format(self.family))
elif toolchain == "Xray":
if self.family != "series7":
raise ValueError("Family '{}' is not supported by the yosys nextpnr toolchain".format(self.family))
self.toolchain = toolchain
@property
@ -519,6 +625,8 @@ class XilinxPlatform(TemplatedPlatform):
return self._ise_required_tools
if self.toolchain == "Symbiflow":
return self._symbiflow_required_tools
if self.toolchain == "Xray":
return self._xray_required_tools
assert False
@property
@ -529,6 +637,8 @@ class XilinxPlatform(TemplatedPlatform):
return self._ise_file_templates
if self.toolchain == "Symbiflow":
return self._symbiflow_file_templates
if self.toolchain == "Xray":
return self._xray_file_templates
assert False
@property
@ -539,6 +649,8 @@ class XilinxPlatform(TemplatedPlatform):
return self._ise_command_templates
if self.toolchain == "Symbiflow":
return self._symbiflow_command_templates
if self.toolchain == "Xray":
return self._xray_command_templates
assert False
def create_missing_domain(self, name):
@ -561,7 +673,7 @@ class XilinxPlatform(TemplatedPlatform):
"ultrascaleplus": "STARTUPE3",
}
if self.family not in STARTUP_PRIMITIVE or self.toolchain == "Symbiflow":
if self.family not in STARTUP_PRIMITIVE or not self.vendor_toolchain:
# Spartan 3 and before lacks a STARTUP primitive with EOS output; use a simple ResetSynchronizer
# in that case, as is the default.
# Symbiflow does not support the STARTUPE2 primitive.
@ -905,7 +1017,7 @@ class XilinxPlatform(TemplatedPlatform):
valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
m = Module()
i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD"), o_invert=invert)
if self.toolchain != "Symbiflow":
if self.vendor_toolchain:
for bit in range(pin.width):
m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUF",
i_I=o[bit],
@ -916,7 +1028,7 @@ class XilinxPlatform(TemplatedPlatform):
return m
def get_tristate(self, pin, port, attrs, invert):
if self.toolchain == "Symbiflow":
if not self.vendor_toolchain:
return super().get_tristate(pin, port, attrs, invert)
self._check_feature("single-ended tristate", pin, attrs,
@ -932,7 +1044,7 @@ class XilinxPlatform(TemplatedPlatform):
return m
def get_input_output(self, pin, port, attrs, invert):
if self.toolchain == "Symbiflow":
if not self.vendor_toolchain:
return super().get_input_output(pin, port, attrs, invert)
self._check_feature("single-ended input/output", pin, attrs,
@ -949,7 +1061,7 @@ class XilinxPlatform(TemplatedPlatform):
return m
def get_diff_input(self, pin, port, attrs, invert):
if self.toolchain == "Symbiflow":
if not self.vendor_toolchain:
return super().get_diff_input(pin, port, attrs, invert)
self._check_feature("differential input", pin, attrs,
@ -964,7 +1076,7 @@ class XilinxPlatform(TemplatedPlatform):
return m
def get_diff_output(self, pin, port, attrs, invert):
if self.toolchain == "Symbiflow":
if not self.vendor_toolchain:
return super().get_diff_output(pin, port, attrs, invert)
self._check_feature("differential output", pin, attrs,
@ -979,7 +1091,7 @@ class XilinxPlatform(TemplatedPlatform):
return m
def get_diff_tristate(self, pin, port, attrs, invert):
if self.toolchain == "Symbiflow":
if not self.vendor_toolchain:
return super().get_diff_tristate(pin, port, attrs, invert)
self._check_feature("differential tristate", pin, attrs,
@ -995,7 +1107,7 @@ class XilinxPlatform(TemplatedPlatform):
return m
def get_diff_input_output(self, pin, port, attrs, invert):
if self.toolchain == "Symbiflow":
if not self.vendor_toolchain:
return super().get_diff_input_output(pin, port, attrs, invert)
self._check_feature("differential input/output", pin, attrs,