From 468375b119711e601fcfe1324b48fa9c34db7a7f Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 24 Oct 2023 08:39:01 +0700 Subject: [PATCH] xilinx platform: add more ignored constraints for yosys+nextpnr --- litex/build/xilinx/openxc7.py | 146 ---------------------------- litex/build/xilinx/platform.py | 13 ++- litex/build/xilinx/yosys_nextpnr.py | 122 +++++++++++++---------- 3 files changed, 77 insertions(+), 204 deletions(-) delete mode 100644 litex/build/xilinx/openxc7.py diff --git a/litex/build/xilinx/openxc7.py b/litex/build/xilinx/openxc7.py deleted file mode 100644 index 33bd242f6..000000000 --- a/litex/build/xilinx/openxc7.py +++ /dev/null @@ -1,146 +0,0 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2020 Antmicro -# Copyright (c) 2020 Florent Kermarrec -# Copyright (c) 2022 Victor Suarez Rovere -# Copyright (c) 2023 Hans Baier -# SPDX-License-Identifier: BSD-2-Clause - -import os -import subprocess -import sys -import math -from typing import NamedTuple, Union, List -import re -from shutil import which - -from migen.fhdl.structure import _Fragment, wrap, Constant -from migen.fhdl.specials import Instance - -from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain -from litex.build.generic_platform import * -from litex.build.xilinx.vivado import _xdc_separator, _format_xdc, _build_xdc -from litex.build import tools -from litex.build.xilinx import common - - -def _unwrap(value): - return value.value if isinstance(value, Constant) else value - - -# XilinxOpenXC7Toolchain ---------------------------------------------------------------------------- - -class XilinxOpenXC7Toolchain(YosysNextPNRToolchain): - attr_translate = {} - - synth_fmt = "json" - constr_fmt = "xdc" - pnr_fmt = "fasm" - packer_cmd = "xc7frames2bit" - - def __init__(self): - super().__init__() - self.dbpart = None - self.family = "xilinx" - self._xc7family = None - self._clock_constraints = "" - self.additional_xdc_commands = [] - self._pre_packer_cmd = ["fasm2frames"] - self._synth_opts = "-flatten -abc9 -arch xc7 " - - xc7_family_map = { - "a": "artix7", - "k": "kintex7", - "s": "spartan7", - "z": "zynq7" - } - - def _check_properties(self): - pattern = re.compile("xc7([aksz])([0-9]+)(.*)-([0-9])") - g = pattern.search(self.platform.device) - if not self.dbpart: - self.dbpart = f"xc7{g.group(1)}{g.group(2)}{g.group(3)}" - - if not self._xc7family: - fam = g.group(1) - self._xc7family = self.xc7_family_map[fam] - - def build_timing_constraints(self, vns): - xdc = [] - xdc.append(_xdc_separator("Clock constraints")) - - for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): - clk_sig = self._vns.get_name(clk) - if name is None: - name = clk_sig - xdc.append( - "create_clock -name {name} -period " + str(period) + - " [get_ports {clk}]".format(name=name, clk=clk_sig)) - - # generate sdc - xdc += self.additional_xdc_commands - self._clock_constraints = "\n".join(xdc) - - def build_io_constraints(self): - tools.write_to_file(self._build_name + ".xdc", _build_xdc(self.named_sc, self.named_pc) + self._clock_constraints) - return (self._build_name + ".xdc", "XDC") - - def _fix_instance(self, instance): - pass - - def finalize(self): - # toolchain-specific fixes - for instance in self.fragment.specials: - if isinstance(instance, Instance): - self._fix_instance(instance) - - chipdb_dir = os.environ.get('CHIPDB') - if chipdb_dir is None or chipdb_dir == "": - print("Error: please specify the directory, where you store your nextpnr-xilinx chipdb files in the environment variable CHIPDB (may be empty)") - exit(1) - - # pnr options - self._pnr_opts += "--chipdb {chipdb_dir}/{dbpart}.bin --write {top}_routed.json".format( - top = self._build_name, - chipdb_dir = chipdb_dir, - dbpart = self.dbpart, - ) - - prjxray_db_dir = os.environ.get('PRJXRAY_DB_DIR') - if prjxray_db_dir is None or prjxray_db_dir == "": - prjxray_db_dir = '/snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/' - - if not os.path.isdir(prjxray_db_dir): - print(f"{prjxray_db_dir} does not exist on your system. \n" + \ - "Do you have the openXC7 toolchain installed? \n" + \ - "You can get it here: https://github.com/openXC7/toolchain-installer") - exit(1) - - # pre packer options - self._pre_packer_opts["fasm2frames"] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( - part = self.platform.device, - db_root = os.path.join(prjxray_db_dir, self._xc7family), - top = self._build_name - ) - # packer options - self._packer_opts += "--part_file {db_dir}/{part}/part.yaml --part_name {part} --frm_file {top}.frames --output_file {top}.bit".format( - db_dir = os.path.join(prjxray_db_dir, self._xc7family), - part = self.platform.device, - top = self._build_name - ) - - return YosysNextPNRToolchain.finalize(self) - - def build(self, platform, fragment, - enable_xpm = False, - **kwargs): - - self.platform = platform - self._check_properties() - - return YosysNextPNRToolchain.build(self, platform, fragment, **kwargs) - - def add_false_path_constraint(self, platform, from_, to): - # FIXME: false path constraints are currently not supported by the openXC7 toolchain - return diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index 3fec9e17c..b188e36dd 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -39,12 +39,9 @@ class XilinxPlatform(GenericPlatform): elif toolchain == "symbiflow" or toolchain == "f4pga": from litex.build.xilinx import f4pga self.toolchain = f4pga.F4PGAToolchain() - elif toolchain == "yosys+nextpnr": + elif toolchain in ["yosys+nextpnr", "openxc7"]: from litex.build.xilinx import yosys_nextpnr - self.toolchain = yosys_nextpnr.XilinxYosysNextpnrToolchain() - elif toolchain == "openxc7": - from litex.build.xilinx import openxc7 - self.toolchain = openxc7.XilinxOpenXC7Toolchain() + self.toolchain = yosys_nextpnr.XilinxYosysNextpnrToolchain(toolchain) else: raise ValueError(f"Unknown toolchain {toolchain}") @@ -62,6 +59,12 @@ class XilinxPlatform(GenericPlatform): if "set_property INTERNAL_VREF" in command: print("WARNING: INTERNAL_VREF constraint removed since not yet supported by yosys-nextpnr flow.") skip = True + if "set_property CFGBVS" in command: + print("WARNING: CFGBVS constraint removed since not yet supported by yosys-nextpnr flow.") + skip = True + if "set_property CONFIG_VOLTAGE" in command: + print("WARNING: CONFIG_VOLTAGE constraint removed since not yet supported by yosys-nextpnr flow.") + skip = True if not skip: GenericPlatform.add_platform_command(self, command, **signals) diff --git a/litex/build/xilinx/yosys_nextpnr.py b/litex/build/xilinx/yosys_nextpnr.py index b8ba75e42..fde84df37 100644 --- a/litex/build/xilinx/yosys_nextpnr.py +++ b/litex/build/xilinx/yosys_nextpnr.py @@ -4,6 +4,7 @@ # Copyright (c) 2020 Antmicro # Copyright (c) 2020 Florent Kermarrec # Copyright (c) 2022 Victor Suarez Rovere +# Copyright (c) 2023 Hans Baier # SPDX-License-Identifier: BSD-2-Clause import os @@ -39,57 +40,52 @@ class XilinxYosysNextpnrToolchain(YosysNextPNRToolchain): pnr_fmt = "fasm" packer_cmd = "xc7frames2bit" - def __init__(self): + def __init__(self, toolchain): + assert toolchain in ["yosys+nextpnr", "openxc7"] + self.is_openxc7 = toolchain == "openxc7" super().__init__() - self.f4pga_device = None - self.bitstream_device = None - self._partname = None - self._pre_packer_cmd = ["fasm2frames.py"] + self.dbpart = None + self._xc7family = None + self._clock_constraints = "" + self.additional_xdc_commands = [] + self._pre_packer_cmd = ["fasm2frames" if self.is_openxc7 else "fasm2frames.py"] self._synth_opts = "-flatten -abc9 -arch xc7 " - def _check_properties(self): - if not self.f4pga_device: - try: - self.f4pga_device = { - # FIXME: fine for now since only a few devices are supported, do more clever device re-mapping. - "xc7a35ticsg324-1L" : "xc7a35t", - "xc7a100tcsg324-1" : "xc7a100t", - "xc7z010clg400-1" : "xc7z010", - "xc7z020clg400-1" : "xc7z020", - }[self.platform.device] - except KeyError: - raise ValueError(f"f4pga_device is not specified") - if not self.bitstream_device: - try: - # bitstream_device points to a directory in prjxray database - # available bitstream_devices: artix7, kintex7, zynq7 - self.bitstream_device = { - "xc7s": "spartan7", - "xc7a": "artix7", - "xc7k": "kintex7", - "xc7z": "zynq7", - }[self.platform.device[:4]] - except KeyError: - raise ValueError(f"Unsupported device: {self.platform.device}") + xc7_family_map = { + "a": "artix7", + "k": "kintex7", + "s": "spartan7", + "z": "zynq7" + } - self._partname = { - "xc7a35ticsg324-1L" : "xc7a35tcsg324-1", - "xc7a100tcsg324-1" : "xc7a100tcsg324-1", - "xc7a200t-sbg484-1" : "xc7a200tsbg484-1", - "xc7z010clg400-1" : "xc7z010clg400-1", - "xc7z020clg400-1" : "xc7z020clg400-1", - }.get(self.platform.device, self.platform.device) + def _check_properties(self): + pattern = re.compile("xc7([aksz])([0-9]+)(.*)-([0-9])") + g = pattern.search(self.platform.device) + if not self.dbpart: + self.dbpart = f"xc7{g.group(1)}{g.group(2)}{g.group(3)}" + + if not self._xc7family: + fam = g.group(1) + self._xc7family = self.xc7_family_map[fam] def build_timing_constraints(self, vns): - self.platform.add_platform_command(_xdc_separator("Clock constraints")) - #for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): - # platform.add_platform_command( - # "create_clock -period " + str(period) + - # " {clk}", clk=clk) - pass #clock constraints not supported + xdc = [] + xdc.append(_xdc_separator("Clock constraints")) + + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig + xdc.append( + "create_clock -name {name} -period " + str(period) + + " [get_ports {clk}]".format(name=name, clk=clk_sig)) + + # generate sdc + xdc += self.additional_xdc_commands + self._clock_constraints = "\n".join(xdc) def build_io_constraints(self): - tools.write_to_file(self._build_name + ".xdc", _build_xdc(self.named_sc, self.named_pc)) + tools.write_to_file(self._build_name + ".xdc", _build_xdc(self.named_sc, self.named_pc) + self._clock_constraints) return (self._build_name + ".xdc", "XDC") def _fix_instance(self, instance): @@ -101,23 +97,44 @@ class XilinxYosysNextpnrToolchain(YosysNextPNRToolchain): if isinstance(instance, Instance): self._fix_instance(instance) + if self.is_openxc7: + chipdb_dir = os.environ.get('CHIPDB') + if chipdb_dir is None or chipdb_dir == "": + print("Error: please specify the directory, where you store your nextpnr-xilinx chipdb files in the environment variable CHIPDB (may be empty)") + exit(1) + else: + chipdb_dir = "/usr/share/nextpnr/xilinx-chipdb" + # pnr options - self._pnr_opts += "--chipdb {chipdb_dir}/{device}.bin --write {top}_routed.json".format( + self._pnr_opts += "--chipdb {chipdb_dir}/{dbpart}.bin --write {top}_routed.json".format( top = self._build_name, - chipdb_dir = "/usr/share/nextpnr/xilinx-chipdb", - device = self.f4pga_device, + chipdb_dir = chipdb_dir, + dbpart = self.dbpart, ) + if self.is_openxc7: + prjxray_db_dir = os.environ.get('PRJXRAY_DB_DIR') + if prjxray_db_dir is None or prjxray_db_dir == "": + prjxray_db_dir = '/snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/' + else: + prjxray_db_dir = f"/usr/share/nextpnr/prjxray-db/ + + if not os.path.isdir(prjxray_db_dir): + print(f"{prjxray_db_dir} does not exist on your system. \n" + \ + "Do you have the openXC7 toolchain installed? \n" + \ + "You can get it here: https://github.com/openXC7/toolchain-installer") + exit(1) + # pre packer options - self._pre_packer_opts["fasm2frames.py"] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( - part = self._partname, - db_root = f"/usr/share/nextpnr/prjxray-db/{self.bitstream_device}", + self._pre_packer_opts[self._pre_packer_cmd] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( + part = self.platform.device, + db_root = os.path.join(prjxray_db_dir, self._xc7family), top = self._build_name ) # packer options self._packer_opts += "--part_file {db_dir}/{part}/part.yaml --part_name {part} --frm_file {top}.frames --output_file {top}.bit".format( - db_dir = f"/usr/share/nextpnr/prjxray-db/{self.bitstream_device}", - part = self._partname, + db_dir = os.path.join(prjxray_db_dir, self._xc7family), + part = self.platform.device, top = self._build_name ) @@ -127,12 +144,11 @@ class XilinxYosysNextpnrToolchain(YosysNextPNRToolchain): enable_xpm = False, **kwargs): - #FIXME self.platform = platform self._check_properties() return YosysNextPNRToolchain.build(self, platform, fragment, **kwargs) def add_false_path_constraint(self, platform, from_, to): - # FIXME: false path constraints are currently not supported by nextpnr-xilinx + # FIXME: false path constraints are currently not supported by the toolchain return