diff --git a/edalize/nextpnr.py b/edalize/nextpnr.py index d222a0abe..4da6b0a3e 100644 --- a/edalize/nextpnr.py +++ b/edalize/nextpnr.py @@ -28,10 +28,21 @@ def configure_main(self): cst_file = "" lpf_file = "" pcf_file = "" + xdc_file = "" pdc_file = "" qsf_file = "" netlist = "" unused_files = [] + + arch = self.tool_options["arch"] + is_interchange = arch == "fpga_interchange" + chipdb = self.tool_options.get("chipdb") + if is_interchange and (chipdb is None): + raise RuntimeError( + "Nextpnr-fpga_interchange require chipdb to be specified." + ) + package = self.tool_options.get("package") + for f in self.files: if f["file_type"] == "CST": if cst_file: @@ -65,6 +76,14 @@ def configure_main(self): ) ) pcf_file = f["name"] + elif f["file_type"] == "XDC": + if xdc_file: + raise RuntimeError( + "Nextpnr only supports one XDC file. Found {} and {}".format( + xdc_file, f["name"] + ) + ) + xdc_file = f["name"] if f["file_type"] == "QSF": if qsf_file: raise RuntimeError( @@ -80,6 +99,26 @@ def configure_main(self): netlist, f["name"] ) ) + if is_interchange: + raise RuntimeError( + "Nextpnr-fpga_interchange requires fpga-interchange logical netlist instead of JSON, found{}".format( + f["name"] + ) + ) + netlist = f["name"] + elif f["file_type"] == "fpgaInterchangeNetlist": + if netlist: + raise RuntimeError( + "Nextpnr only supports one netlist. Found {} and {}".format( + netlist, f["name"] + ) + ) + if not is_interchange: + raise RuntimeError( + "Non-interchange variants of Nextpnr require JSON netlist, found{}".format( + f["name"] + ) + ) netlist = f["name"] else: unused_files.append(f) @@ -93,7 +132,6 @@ def configure_main(self): # Write Makefile commands = EdaCommands() - arch = self.flow_config["arch"] arch_options = [] if arch == "ecp5": targets = self.name + ".config" @@ -125,15 +163,26 @@ def configure_main(self): targets = self.name + ".pack" constraints = ["--cst", cst_file] if cst_file else [] output = ["--write", targets] + elif arch == "fpga_interchange": + targets = self.name + ".phys" + constraints = ["--xdc", xdc_file] + output = ["--phys", targets] else: targets = self.name + ".asc" constraints = ["--pcf", pcf_file] if pcf_file else [] output = ["--asc", targets] depends = netlist - command = ["nextpnr-" + arch, "-l", "next.log"] + command = ["nextpnr-" + arch] command += arch_options + self.tool_options.get("nextpnr_options", []) - command += constraints + ["--json", depends] + output + command += constraints + if is_interchange: + command += ["--netlist", depends, "--chipdb", chipdb] + else: + command += ["--json", depends] + if package is not None: + command += ["--package", package] + command += output # CLI target commands.add(command, [targets], [depends]) @@ -141,3 +190,6 @@ def configure_main(self): # GUI target commands.add(command + ["--gui"], ["build-gui"], [depends]) self.commands = commands.commands + + commands.set_default_target(targets) + commands.write(os.path.join(self.work_root, "Makefile")) diff --git a/edalize/tools/nextpnr.py b/edalize/tools/nextpnr.py index d1007c324..30dbcac54 100644 --- a/edalize/tools/nextpnr.py +++ b/edalize/tools/nextpnr.py @@ -26,8 +26,14 @@ def configure(self, edam): cst_file = "" lpf_file = "" pcf_file = "" + xdc_file = "" netlist = "" unused_files = [] + + arch = self.tool_options["arch"] + + is_interchange = arch == "fpga_interchange" + for f in self.files: file_type = f.get("file_type", "") if file_type == "CST": @@ -38,7 +44,7 @@ def configure(self, edam): ) ) cst_file = f["name"] - if file_type == "LPF": + elif file_type == "LPF": if lpf_file: raise RuntimeError( "Nextpnr only supports one LPF file. Found {} and {}".format( @@ -46,7 +52,7 @@ def configure(self, edam): ) ) lpf_file = f["name"] - if file_type == "PCF": + elif file_type == "PCF": if pcf_file: raise RuntimeError( "Nextpnr only supports one PCF file. Found {} and {}".format( @@ -54,6 +60,13 @@ def configure(self, edam): ) ) pcf_file = f["name"] + elif file_type == "XDC": + if xdc_file: + raise RuntimeError( + "Nextpnr only supports one XDC file. Found {} and {}".format( + xdc_file, f["name"] + ) + ) elif file_type == "jsonNetlist": if netlist: raise RuntimeError( @@ -61,6 +74,26 @@ def configure(self, edam): netlist, f["name"] ) ) + if is_interchange: + raise RuntimeError( + "Nextpnr-fpga_interchange requires fpga-interchange logical netlist instead of JSON, found{}".format( + f["name"] + ) + ) + netlist = f["name"] + elif file_type == "fpgaInterchangeNetlist": + if netlist: + raise RuntimeError( + "Nextpnr only supports one netlist. Found {} and {}".format( + netlist, f["name"] + ) + ) + if not is_interchange: + raise RuntimeError( + "Non-interchange variants of Nextpnr require JSON netlist, found{}".format( + f["name"] + ) + ) netlist = f["name"] else: unused_files.append(f) @@ -75,7 +108,6 @@ def configure(self, edam): # Write Makefile commands = EdaCommands() - arch = self.tool_options["arch"] arch_options = [] if arch == "ecp5": targets = self.name + ".config" @@ -89,6 +121,10 @@ def configure(self, edam): targets = self.name + ".pack" constraints = ["--cst", cst_file] if cst_file else [] output = ["--write", targets] + elif arch == "fpga_interchange": + targets = self.name + ".phys" + constraints = ["--xdc", xdc_file] + output = ["--phys", targets] else: targets = self.name + ".asc" constraints = ["--pcf", pcf_file] if pcf_file else [] @@ -97,7 +133,12 @@ def configure(self, edam): depends = netlist command = ["nextpnr-" + arch, "-l", "next.log"] command += arch_options + self.tool_options.get("nextpnr_options", []) - command += constraints + ["--json", depends] + output + command += constraints + if is_interchange: + command += ["--netlist", depends] + else: + command += ["--json", depends] + command += output # CLI target commands.add(command, [targets], [depends])