Exemple #1
0
    def configure(self, edam):
        super().configure(edam)

        incdirs = []
        sv_files = []
        unused_files = []

        for f in self.files:
            if f.get("file_type").startswith("systemVerilogSource"):
                if not self._add_include_dir(f, incdirs):
                    sv_files.append(f["name"])
            else:
                unused_files.append(f)

        output_file = self.name + ".v"
        self.edam = edam.copy()
        self.edam["files"] = unused_files
        self.edam["files"].append({
            "name": output_file,
            "file_type": "verilogSource",
        })

        sv2v_options = self.tool_options.get("sv2v_options", [])

        commands = EdaCommands()
        commands.add(
            ["sv2v", "-w", output_file] + sv2v_options +
            ["-I" + d for d in incdirs] + sv_files,
            [output_file],
            sv_files,
        )

        self.commands = commands.commands
Exemple #2
0
    def configure(self, edam):
        super().configure(edam)

        unused_files = []

        asc_file = ""
        bin_file = ""
        for f in self.files:
            if f["file_type"] == "iceboxAscii":
                if asc_file:
                    raise RuntimeError(
                        "Icepack only supports one input file. Found {} and {}".format(
                            asc_file, f["name"]
                        )
                    )
                asc_file = f["name"]
            else:
                unused_files.append(f)

        if not asc_file:
            raise RuntimeError("No input file specified for icepack")

        bin_file = os.path.splitext(asc_file)[0] + ".bin"
        self.edam = edam.copy()
        self.edam["files"] = unused_files
        self.edam["files"].append({"name": bin_file, "file_type": "binary"})

        # Image generation
        depends = asc_file
        targets = bin_file
        command = ["icepack", depends, targets]

        commands = EdaCommands()
        commands.add(command, [targets], [depends])
        self.commands = commands.commands
Exemple #3
0
    def configure(self, edam):
        super().configure(edam)
        unused_files = []

        asc_file = ""
        for f in self.files:
            if f["file_type"] == "iceboxAscii":
                if asc_file:
                    raise RuntimeError(
                        "Icetime only supports one input file. Found {} and {}"
                        .format(asc_file, f["name"]))
                asc_file = f["name"]
            else:
                unused_files.append(f)

        if not asc_file:
            raise RuntimeError("No input file specified for icetime")

        tim_file = os.path.splitext(asc_file)[0] + ".tim"
        self.edam["files"] = unused_files
        self.edam["files"].append({"name": tim_file, "file_type": "report"})

        # Image generation
        depends = asc_file
        targets = tim_file
        command = ["icetime", "-r", targets] + self.tool_options.get(
            "icetime_options", [])
        command.append(depends)

        commands = EdaCommands()
        commands.add(command, [targets], [depends])
        commands.add([], ["timing"], [targets])
        self.commands = commands.commands
Exemple #4
0
    def configure(self, edam):
        super().configure(edam)

        incdirs = []
        file_table = []
        unused_files = []

        depfiles = []

        # Filter out input files
        for f in self.files:
            src = ""
            if "file_type" in f:
                file_type = f.get("file_type", "")
                if file_type.startswith("verilogSource"):
                    src = f["name"]
                elif file_type.startswith("systemVerilogSource"):
                    src = "-sv " + f["name"]

                if src:
                    depfiles.append(f["name"])
                    if not self._add_include_dir(f, incdirs):
                        file_table.append(src)
                else:
                    unused_files.append(f)

        # Create output EDAM
        output_file = "slpp_all/surelog.uhdm"
        self.edam = edam.copy()
        self.edam["files"] = unused_files
        self.edam["files"].append({"name": output_file, "file_type": "uhdm"})

        # Handle verilog defines
        verilog_defines = []
        for key, value in self.vlogdefine.items():
            verilog_params.append(f"+define+{key}={value}")

        # Handle verilog parameters
        verilog_params = []
        for key, value in self.vlogparam.items():
            verilog_params.append(f"-P{key}={value}")

        commands = EdaCommands()

        commands.add(
            ["surelog", "-top", self.toplevel] +
            self.tool_options.get("surelog_options", []) + ["-parse"] +
            verilog_defines + verilog_params + ["-I" + d
                                                for d in incdirs] + file_table,
            [output_file],
            depfiles,
        )

        self.commands = commands.commands
Exemple #5
0
    def __init__(self, edam, work_root, verbose=False):
        self.edam = edam

        # Extract all options that affects the flow rather than
        # just a single tool
        self.flow_options = self.extract_flow_options()

        # Rearrange tool_options so that each tool gets their
        # own tool_options
        self.extract_tool_options()

        self.work_root = work_root

        self.stdout = None
        self.stderr = None
        self.commands = EdaCommands()
Exemple #6
0
    def configure_main(self):
        # Pass apicula tool options to yosys and nextpnr
        self.edam["tool_options"] = {
            "yosys": {
                "arch": "gowin",
                "output_format": "json",
                "yosys_synth_options": [f"-json {self.name}.json"]
                + self.tool_options.get("yosys_synth_options", []),
                "yosys_as_subtool": True,
                "yosys_template": self.tool_options.get("yosys_template"),
            },
            "nextpnr": {
                "device": self.tool_options.get("device"),
                "nextpnr_options": self.tool_options.get("nextpnr_options", []),
            },
        }

        yosys = Yosys(self.edam, self.work_root)
        yosys.configure()

        nextpnr = Nextpnr(yosys.edam, self.work_root)
        nextpnr.flow_config = {"arch": "gowin"}
        nextpnr.configure()

        # Write Makefile
        commands = EdaCommands()
        commands.commands = yosys.commands

        commands.commands += nextpnr.commands

        # Image generation
        depends = self.name + ".pack"
        targets = self.name + ".fs"
        command = [
            "gowin_pack",
            "-d",
            self.tool_options.get("device"),
            "-o",
            targets,
            depends,
        ]
        commands.add(command, [targets], [depends])

        commands.set_default_target(targets)
        commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #7
0
    def configure_main(self):
        # Pass trellis tool options to yosys and nextpnr
        self.edam["tool_options"] = {
            "yosys": {
                "arch":
                "nexus",
                "output_format":
                "json",
                "yosys_synth_options":
                self.tool_options.get("yosys_synth_options", []),
                "yosys_as_subtool":
                True,
                "yosys_template":
                self.tool_options.get("yosys_template"),
            },
            "nextpnr": {
                "device": self.tool_options.get("device"),
                "nextpnr_options":
                self.tool_options.get("nextpnr_options", []),
            },
        }

        yosys = Yosys(self.edam, self.work_root)
        yosys.configure()

        nextpnr = Nextpnr(yosys.edam, self.work_root)
        nextpnr.flow_config = {"arch": "nexus"}
        nextpnr.configure()

        # Write Makefile
        commands = EdaCommands()
        commands.commands = yosys.commands

        commands.commands += nextpnr.commands

        # Image generation
        depends = self.name + ".fasm"
        targets = self.name + ".bit"
        command = ["prjoxide", "pack", depends, targets]
        commands.add(command, [targets], [depends])

        commands.set_default_target(self.name + ".bit")
        commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #8
0
    def configure_main(self):
        # pass mistral tool option to yosys and nextpnr

        self.edam["tool_options"] = {
            "yosys": {
                "arch":
                "intel_alm",
                "output_format":
                "json",
                "yosys_synth_options":
                self.tool_options.get("yosys_synth_options", []),
                "yosys_as_subtool":
                True,
                "yosys_template":
                self.tool_options.get("yosys_template"),
            },
            "nextpnr": {
                "device": self.tool_options.get("device"),
                "nextpnr_options":
                self.tool_options.get("nextpnr_options", []),
            },
        }

        yosys = Yosys(self.edam, self.work_root)
        yosys.configure()

        nextpnr = Nextpnr(yosys.edam, self.work_root)
        nextpnr.flow_config = {"arch": "mistral"}
        nextpnr.configure()

        # Write Makefile
        commands = EdaCommands()

        commands.commands = yosys.commands

        commands.commands += nextpnr.commands

        # Image generation

        commands.set_default_target(self.name + ".rbf")

        commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #9
0
    def configure_vpr(self):
        (src_files, incdirs) = self._get_fileset_files(force_slash=True)

        has_vhdl = "vhdlSource" in [x.file_type for x in src_files]
        has_vhdl2008 = "vhdlSource-2008" in [x.file_type for x in src_files]

        if has_vhdl or has_vhdl2008:
            logger.error("VHDL files are not supported in Yosys")
        file_list = []
        timing_constraints = []
        pins_constraints = []
        placement_constraints = []

        for f in src_files:
            if f.file_type in ["verilogSource"]:
                file_list.append(f.name)
            if f.file_type in ["SDC"]:
                timing_constraints.append(f.name)
            if f.file_type in ["PCF"]:
                pins_constraints.append(f.name)
            if f.file_type in ["xdc"]:
                placement_constraints.append(f.name)

        part = self.tool_options.get("part")
        package = self.tool_options.get("package")
        vendor = self.tool_options.get("vendor")

        if not part:
            logger.error('Missing required "part" parameter')
        if not package:
            logger.error('Missing required "package" parameter')

        if vendor == "xilinx":
            if "xc7a" in part:
                bitstream_device = "artix7"
            if "xc7z" in part:
                bitstream_device = "zynq7"
            if "xc7k" in part:
                bitstream_device = "kintex7"

            partname = part + package

            # a35t are in fact a50t
            # leave partname with 35 so we access correct DB
            if part == "xc7a35t":
                part = "xc7a50t"
            device_suffix = "test"
        elif vendor == "quicklogic":
            partname = package
            device_suffix = "wlcsp"
            bitstream_device = part + "_" + device_suffix

        _vo = self.tool_options.get("vpr_options")
        vpr_options = ["--additional_vpr_options", f'"{_vo}"'] if _vo else []
        pcf_opts = ["-p"] + pins_constraints if pins_constraints else []
        sdc_opts = ["-s"] + timing_constraints if timing_constraints else []
        xdc_opts = ["-x"
                    ] + placement_constraints if placement_constraints else []

        commands = EdaCommands()
        # Synthesis
        targets = self.toplevel + ".eblif"
        command = ["symbiflow_synth", "-t", self.toplevel]
        command += ["-v"] + file_list
        command += ["-d", bitstream_device]
        command += ["-p" if vendor == "xilinx" else "-P", partname]
        command += xdc_opts
        commands.add(command, [targets], [])

        # P&R
        eblif_opt = ["-e", self.toplevel + ".eblif"]
        device_opt = ["-d", part + "_" + device_suffix]

        depends = self.toplevel + ".eblif"
        targets = self.toplevel + ".net"
        command = ["symbiflow_pack"
                   ] + eblif_opt + device_opt + sdc_opts + vpr_options
        commands.add(command, [targets], [depends])

        depends = self.toplevel + ".net"
        targets = self.toplevel + ".place"
        command = ["symbiflow_place"] + eblif_opt + device_opt
        command += ["-n", depends, "-P", partname]
        command += sdc_opts + pcf_opts + vpr_options
        commands.add(command, [targets], [depends])

        depends = self.toplevel + ".place"
        targets = self.toplevel + ".route"
        command = ["symbiflow_route"] + eblif_opt + device_opt
        command += sdc_opts + vpr_options
        commands.add(command, [targets], [depends])

        depends = self.toplevel + ".route"
        targets = self.toplevel + ".fasm"
        command = ["symbiflow_write_fasm"] + eblif_opt + device_opt
        command += sdc_opts + vpr_options
        commands.add(command, [targets], [depends])

        depends = self.toplevel + ".fasm"
        targets = self.toplevel + ".bit"
        command = ["symbiflow_write_bitstream"] + ["-d", bitstream_device]
        command += ["-f", depends]
        command += ["-p" if vendor == "xilinx" else "-P", partname]
        command += ["-b", targets]
        commands.add(command, [targets], [depends])

        commands.set_default_target(targets)
        commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #10
0
    def configure_nextpnr(self):
        (src_files, incdirs) = self._get_fileset_files(force_slash=True)
        vendor = self.tool_options.get("vendor")

        # Yosys configuration
        yosys_synth_options = self.tool_options.get("yosys_synth_options", "")
        yosys_template = self.tool_options.get("yosys_template")
        yosys_edam = {
            "files": self.files,
            "name": self.name,
            "toplevel": self.toplevel,
            "parameters": self.parameters,
            "tool_options": {
                "yosys": {
                    "arch": vendor,
                    "output_format": "json",
                    "yosys_synth_options": yosys_synth_options,
                    "yosys_template": yosys_template,
                    "yosys_as_subtool": True,
                }
            },
        }

        yosys = getattr(import_module("edalize.yosys"),
                        "Yosys")(yosys_edam, self.work_root)
        yosys.configure()

        # Nextpnr configuration
        arch = self.tool_options.get("arch")
        if arch not in self.archs:
            logger.error(
                'Missing or invalid "arch" parameter: {} in "tool_options"'.
                format(arch))

        package = self.tool_options.get("package")
        if not package:
            logger.error('Missing required "package" parameter')

        part = self.tool_options.get("part")
        if not part:
            logger.error('Missing required "part" parameter')

        target_family = None
        for family in getattr(self, "fpga_interchange_families"):
            if family in part:
                target_family = family
                break

        if target_family is None and arch == "fpga_interchange":
            logger.error(
                "Couldn't find family for part: {}. Available families: {}".
                format(part,
                       ", ".join(getattr(self, "fpga_interchange_families"))))

        chipdb = None
        device = None
        placement_constraints = []

        for f in src_files:
            if f.file_type in ["bba"]:
                chipdb = f.name
            elif f.file_type in ["device"]:
                device = f.name
            elif f.file_type in ["xdc"]:
                placement_constraints.append(f.name)
            else:
                continue

        if not chipdb:
            logger.error("Missing required chipdb file")

        if placement_constraints == []:
            logger.error("Missing required XDC file(s)")

        if device is None and arch == "fpga_interchange":
            logger.error(
                'Missing required ".device" file for "fpga_interchange" arch')

        nextpnr_options = self.tool_options.get("nextpnr_options", "")
        partname = part + package
        # Strip speedgrade string when using fpga_interchange
        package = package.split("-")[0] if arch == "fpga_interchange" else None

        if "xc7a" in part:
            bitstream_device = "artix7"
        if "xc7z" in part:
            bitstream_device = "zynq7"
        if "xc7k" in part:
            bitstream_device = "kintex7"

        depends = self.name + ".json"
        xdcs = []
        for x in placement_constraints:
            xdcs += ["--xdc", x]

        commands = EdaCommands()
        commands.commands = yosys.commands
        if arch == "fpga_interchange":
            commands.header += """ifndef INTERCHANGE_SCHEMA_PATH
$(error Environment variable INTERCHANGE_SCHEMA_PATH was not found. It should be set to <fpga-interchange-schema path>/interchange)
endif

"""
            targets = self.name + ".netlist"
            command = ["python", "-m", "fpga_interchange.yosys_json"]
            command += ["--schema_dir", "$(INTERCHANGE_SCHEMA_PATH)"]
            command += ["--device", device]
            command += ["--top", self.toplevel]
            command += [depends, targets]
            commands.add(command, [targets], [depends])

            depends = self.name + ".netlist"
            targets = self.name + ".phys"
            command = ["nextpnr-" + arch, "--chipdb", chipdb]
            command += ["--package", package]
            command += xdcs
            command += ["--netlist", depends]
            command += ["--write", self.name + ".routed.json"]
            command += ["--phys", targets]
            command += [nextpnr_options]
            commands.add(command, [targets], [depends])

            depends = self.name + ".phys"
            targets = self.name + ".fasm"
            command = ["python", "-m", "fpga_interchange.fasm_generator"]
            command += ["--schema_dir", "$(INTERCHANGE_SCHEMA_PATH)"]
            command += [
                "--family",
                family,
                device,
                self.name + ".netlist",
                depends,
                targets,
            ]
            commands.add(command, [targets], [depends])
        else:
            targets = self.name + ".fasm"
            command = ["nextpnr-" + arch, "--chipdb", chipdb]
            command += xdcs
            command += ["--json", depends]
            command += ["--write", self.name + ".routed.json"]
            command += ["--fasm", targets]
            command += ["--log", "nextpnr.log"]
            command += [nextpnr_options]
            commands.add(command, [targets], [depends])

        depends = self.name + ".fasm"
        targets = self.name + ".bit"
        command = ["symbiflow_write_bitstream", "-d", bitstream_device]
        command += ["-f", depends, "-p", partname, "-b", targets]
        commands.add(command, [targets], [depends])

        commands.set_default_target(targets)
        commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #11
0
    def configure(self, edam):
        super().configure(edam)
        cst_file = ""
        lpf_file = ""
        pcf_file = ""
        netlist = ""
        unused_files = []
        for f in self.files:
            file_type = f.get("file_type", "")
            if file_type == "CST":
                if cst_file:
                    raise RuntimeError(
                        "Nextpnr only supports one CST file. Found {} and {}".
                        format(cst_file, f["name"]))
                cst_file = f["name"]
            if file_type == "LPF":
                if lpf_file:
                    raise RuntimeError(
                        "Nextpnr only supports one LPF file. Found {} and {}".
                        format(pcf_file, f["name"]))
                lpf_file = f["name"]
            if file_type == "PCF":
                if pcf_file:
                    raise RuntimeError(
                        "Nextpnr only supports one PCF file. Found {} and {}".
                        format(pcf_file, f["name"]))
                pcf_file = f["name"]
            elif file_type == "jsonNetlist":
                if netlist:
                    raise RuntimeError(
                        "Nextpnr only supports one netlist. Found {} and {}".
                        format(netlist, f["name"]))
                netlist = f["name"]
            else:
                unused_files.append(f)

        self.edam = edam.copy()
        self.edam["files"] = unused_files
        of = [
            {
                "name": self.name + ".asc",
                "file_type": "iceboxAscii"
            },
        ]
        self.edam["files"] += of

        # Write Makefile
        commands = EdaCommands()

        arch = self.tool_options["arch"]
        arch_options = []
        if arch == "ecp5":
            targets = self.name + ".config"
            constraints = ["--lpf", lpf_file] if lpf_file else []
            output = ["--textcfg", targets]
        elif arch == "gowin":
            device = self.tool_options.get("device")
            if not device:
                raise RuntimeError(
                    "Missing required option 'device' for nextpnr-gowin")
            arch_options += ["--device", device]
            targets = self.name + ".pack"
            constraints = ["--cst", cst_file] if cst_file else []
            output = ["--write", 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 += arch_options + self.tool_options.get("nextpnr_options", [])
        command += constraints + ["--json", depends] + output

        # CLI target
        commands.add(command, [targets], [depends])

        # GUI target
        commands.add(command + ["--gui"], ["build-gui"], [depends])
        self.commands = commands.commands
Exemple #12
0
    def configure_main(self):
        (src_files, incdirs) = self._get_fileset_files()
        synth_out = self.name + "_synth.v"

        device = self.tool_options.get("device")
        if not device:
            raise RuntimeError("Missing required option 'device' for p_r")

        match = re.search("^CCGM1A([1-9]{1,2})$", device)
        if not match:
            raise RuntimeError("{} is not known device name".format(device))

        device_number = match.groups()[0]
        if device_number not in ["1", "2", "4", "9", "16", "25"]:
            raise RuntimeError(
                "Rel. size {} is not unsupported".format(device_number))

        ccf_file = None

        for f in src_files:
            if f.file_type == "CCF":
                if ccf_file:
                    raise RuntimeError(
                        "p_r only supports one ccf file. Found {} and {}".
                        format(ccf_file, f.name))
                else:
                    ccf_file = f.name

        # Pass trellis tool options to yosys
        self.edam["tool_options"] = {
            "yosys": {
                "arch":
                "gatemate",
                "output_format":
                "verilog",
                "output_name":
                synth_out,
                "yosys_synth_options":
                self.tool_options.get("yosys_synth_options", []),
                "yosys_as_subtool":
                True,
                "yosys_template":
                self.tool_options.get("yosys_template"),
            },
        }

        yosys = Yosys(self.edam, self.work_root)
        yosys.configure()

        # Write Makefile
        commands = EdaCommands()
        commands.commands = yosys.commands

        # PnR & image generation
        targets = self.name + "_00.cfg.bit"
        command = [
            "p_r",
            "-A",
            device_number,
            "-i",
            synth_out,
            "-o",
            self.name,
            "-lib",
            "ccag",
            " ".join(self.tool_options.get("p_r_options", "")),
        ]
        if ccf_file is not None:
            command += ["-ccf", ccf_file]
        commands.add(command, [targets], [synth_out])

        commands.set_default_target(targets)
        commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #13
0
    def configure(self, edam):
        """
        Configuration is the first phase of the build.

        This writes the project TCL files and Makefile. It first collects all
        sources, IPs and constraints and then writes them to the TCL file along
        with the build steps.
        """
        super().configure(edam)
        src_files = []
        incdirs = []
        edif_files = []
        has_vhdl2008 = False
        has_xci = False
        unused_files = []
        bd_files = []

        for f in self.files:
            cmd = ""
            if f["file_type"].startswith("verilogSource"):
                cmd = "read_verilog"
            elif f["file_type"].startswith("systemVerilogSource"):
                cmd = "read_verilog -sv"
            elif f["file_type"] == "tclSource":
                cmd = "source"
            elif f["file_type"] == "edif":
                cmd = "read_edif"
                edif_files.append(f["name"])
            elif f["file_type"].startswith("vhdlSource"):
                cmd = "read_vhdl"
                if f["file_type"] == "vhdlSource-2008":
                    has_vhdl2008 = True
                    cmd += " -vhdl2008"
                if f.get("logical_name"):
                    cmd += " -library " + f["logical_name"]
            elif f["file_type"] == "xci":
                cmd = "read_ip"
                has_xci = True
            elif f["file_type"] == "xdc":
                cmd = "read_xdc"
            elif f["file_type"] == "SDC":
                cmd = "read_xdc -unmanaged"
            elif f["file_type"] == "mem":
                cmd = "read_mem"
            elif f["file_type"] == "bd":
                cmd = "read_bd"
                bd_files.append(f["name"])

            if cmd:
                if not self._add_include_dir(f, incdirs):
                    src_files.append(cmd + " {" + f["name"] + "}")
            else:
                unused_files.append(f)
        template_vars = {
            "name": self.name,
            "src_files": "\n".join(src_files),
            "incdirs": incdirs + ["."],
            "tool_options": self.tool_options,
            "toplevel": self.toplevel,
            "vlogparam": self.vlogparam,
            "vlogdefine": self.vlogdefine,
            "generic": self.generic,
            "netlist_flow": bool(edif_files),
            "has_vhdl2008": has_vhdl2008,
            "has_xci": has_xci,
            "bd_files": bd_files,
        }
        self.render_template("vivado-project.tcl.j2", self.name + ".tcl",
                             template_vars)

        jobs = self.tool_options.get("jobs", None)

        run_template_vars = {
            "jobs": " -jobs " + str(jobs) if jobs is not None else ""
        }

        self.render_template("vivado-run.tcl.j2", self.name + "_run.tcl",
                             run_template_vars)

        synth_template_vars = {
            "jobs": " -jobs " + str(jobs) if jobs is not None else ""
        }

        self.render_template("vivado-synth.tcl.j2", self.name + "_synth.tcl",
                             synth_template_vars)
        # Write Makefile
        commands = EdaCommands()

        vivado_command = ["vivado", "-notrace", "-mode", "batch", "-source"]

        # Create project file
        project_file = self.name + ".xpr"
        tcl_file = [self.name + ".tcl"]
        commands.add(vivado_command + tcl_file, [project_file],
                     tcl_file + edif_files)
        synth = self.tool_options.get("synth", "vivado")
        if synth == "vivado":
            depends = [f"{self.name}_synth.tcl", project_file]
            targets = [f"{self.name}.runs/synth_1/__synthesis_is_complete__"]
            commands.add(vivado_command + depends, targets, depends)
        else:
            targets = edif_files

        commands.add([], ["synth"], targets)

        # Bitstream generation
        run_tcl = self.name + "_run.tcl"
        depends = [run_tcl, project_file]
        bitstream = self.name + ".bit"
        commands.add(vivado_command + depends, [bitstream], depends)

        commands.add(["vivado", project_file], ["build-gui"], [project_file])

        depends = [self.name + "_pgm.tcl", bitstream]
        command = [
            "vivado",
            "-quiet",
            "-nolog",
            "-notrace",
            "-mode",
            "batch",
            "-source",
            f"{self.name}_pgm.tcl",
            "-tclargs",
        ]
        part = self.tool_options.get("part", "")
        command += [part] if part else []
        command += [bitstream]
        commands.add(command, ["pgm"], depends)

        commands.set_default_target(bitstream)
        commands.write(os.path.join(self.work_root, "Makefile"))
        self.commands = commands.commands
        self.render_template("vivado-program.tcl.j2", self.name + "_pgm.tcl")
Exemple #14
0
    def configure(self, edam):
        """
        Configuration is the first phase of the build.

        This writes the project TCL files and Makefile. It first collects all
        sources, IPs and constraints and then writes them to the TCL file along
        with the build steps.
        """
        super().configure(edam)

        src_files = []
        incdirs = set()

        file_netlist = []
        timing_constraints = []

        for f in src_files:
            if f.file_type in ["blif", "eblif"]:
                file_netlist.append(f.name)
            if f.file_type in ["SDC"]:
                timing_constraints.append(f.name)

        arch_xml = self.tool_options.get("arch_xml")
        if not arch_xml:
            logger.error('Missing required "arch" parameter')

        _vo = self.tool_options.get("vpr_options")

        vpr_options = _vo if _vo else []
        sdc_opts = ["--sdc_file"
                    ] + timing_constraints if timing_constraints else []

        commands = EdaCommands()

        depends = self.name + ".blif"
        targets = self.name + ".net"
        command = ["vpr", arch_xml, self.name + ".blif", "--pack"]
        command += sdc_opts + vpr_options
        commands.add(command, [targets], [depends])

        depends = self.name + ".net"
        targets = self.name + ".place"
        command = ["vpr", arch_xml, self.name + ".blif", "--place"]
        command += sdc_opts + vpr_options
        commands.add(command, [targets], [depends])

        depends = self.name + ".place"
        targets = self.name + ".route"
        command = ["vpr", arch_xml, self.name + ".blif", "--route"]
        command += sdc_opts + vpr_options
        commands.add(command, [targets], [depends])

        depends = self.name + ".route"
        targets = self.name + ".analysis"
        command = ["vpr", arch_xml, self.name + ".blif", "--analysis"]
        command += sdc_opts + vpr_options
        commands.add(command, [targets], [depends])

        for ext in [".net", ".place", ".route", ".analysis"]:
            self.edam["files"].append({
                "name": self.name + str(ext),
                "file_type": "vpr_" + str(ext[1:])
            })

        self.commands = commands.commands
        commands.set_default_target(targets)
        commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #15
0
    def configure_main(self):
        # write Yosys tcl script file

        yosys_template = self.tool_options.get("yosys_template")

        incdirs = []
        file_table = []
        unused_files = []

        for f in self.files:
            cmd = ""
            if f["file_type"].startswith("verilogSource"):
                cmd = "read_verilog"
            elif f["file_type"].startswith("systemVerilogSource"):
                cmd = "read_verilog -sv"
            elif f["file_type"] == "tclSource":
                cmd = "source"

            if cmd:
                if not self._add_include_dir(f, incdirs):
                    file_table.append(cmd + " {" + f["name"] + "}")
            else:
                unused_files.append(f)

        self.edam["files"] = unused_files

        output_format = self.tool_options.get("output_format", "blif")
        default_target = f"{self.name}.{output_format}"

        self.edam["files"].append({
            "name":
            default_target,
            "file_type":
            "jsonNetlist" if output_format == "json" else output_format,
        })

        verilog_defines = []
        for key, value in self.vlogdefine.items():
            verilog_defines.append("{{{key} {value}}}".format(key=key,
                                                              value=value))

        verilog_params = []
        for key, value in self.vlogparam.items():
            if type(value) is str:
                value = '{"' + value + '"}'
            _s = r"chparam -set {} {} {}"
            verilog_params.append(
                _s.format(key, self._param_value_str(value), self.toplevel))

        arch = self.tool_options.get("arch", None)

        if not arch:
            logger.error("ERROR: arch is not defined.")

        template = yosys_template or "edalize_yosys_template.tcl"
        template_vars = {
            "verilog_defines":
            "{" + " ".join(verilog_defines) + "}",
            "verilog_params":
            "\n".join(verilog_params),
            "file_table":
            "\n".join(file_table),
            "incdirs":
            " ".join(["-I" + d for d in incdirs]),
            "top":
            self.toplevel,
            "synth_command":
            "synth_" + arch,
            "synth_options":
            " ".join(self.tool_options.get("yosys_synth_options", "")),
            "write_command":
            "write_" + output_format,
            "output_format":
            output_format,
            "output_opts":
            "-pvector bra " if arch == "xilinx" else "",
            "yosys_template":
            template,
            "name":
            self.name,
        }

        self.render_template("edalize_yosys_procs.tcl.j2",
                             "edalize_yosys_procs.tcl", template_vars)

        if not yosys_template:
            self.render_template("yosys-script-tcl.j2",
                                 "edalize_yosys_template.tcl", template_vars)

        commands = EdaCommands()
        commands.add(
            ["yosys", "-l", "yosys.log", "-p", f"'tcl {template}'"],
            [default_target],
            [template],
        )
        if self.tool_options.get("yosys_as_subtool"):
            self.commands = commands.commands
        else:
            commands.set_default_target(f"{self.name}.{output_format}")
            commands.write(os.path.join(self.work_root, "Makefile"))
Exemple #16
0
    def configure(self, edam):
        super().configure(edam)
        analyze_options = self.tool_options.get("analyze_options", [])

        # Check of std=xx analyze option, this overyides the dynamic determination of vhdl standard
        import re

        rx = re.compile("^--std=([0-9]+)")
        m = None
        for o in analyze_options:
            m = rx.match(o)
            if m:
                stdarg = [m.group()]
                analyze_options.remove(o)
                break

        if m:
            logger.warning(
                "Analyze option "
                + m.group()
                + " given, will override any vhdlSource-xxxx specification\n"
            )
            standard = m.group(1)
        else:
            # ghdl does not support mixing incompatible versions
            # specifying 93c as std should allow 87 syntax
            # 2008 can't be combined so try to parse everthing with 08 std

            has87 = has93 = has08 = False
            for f in self.files:
                if f["file_type"] == "vhdlSource-87":
                    has87 = True
                elif f["file_type"] == "vhdlSource-93":
                    has93 = True
                elif f["file_type"] == "vhdlSource-2008":
                    has08 = True
            stdarg = []
            if has08:
                if has87 or has93:
                    logger.warning(
                        "ghdl can't mix vhdlSource-2008 with other standard version\n"
                        + "Trying with treating all as vhdlSource-2008"
                    )
                stdarg = ["--std=08"]
            elif has87 and has93:
                stdarg = ["--std=93c"]
            elif has87:
                stdarg = ["--std=87"]
            elif has93:
                stdarg = ["--std=93"]
            else:
                stdarg = ["--std=93c"]

            standard = rx.match(stdarg[0]).group(1)

        run_options = self.tool_options.get("run_options", [])

        analyze_options = " ".join(analyze_options)

        _vhdltypes = ("vhdlSource", "vhdlSource-87", "vhdlSource-93", "vhdlSource-2008")

        libraries = {}
        library_options = "--work={lib} --workdir=./{lib}"
        ghdlimport = ""
        vhdl_sources = ""

        # GHDL versions older than 849a25e0 don't support the dot notation (e.g.
        # my_lib.top_design) for the top level.
        # Nonetheless, we unconditionally split the library and the primary unit,
        # if the user specified the top level using the dot notation.
        top = self.toplevel.split(".")

        if len(top) > 2:
            logger.error("Invalid dot notation in toplevel: {}".format(self.toplevel))

        top_libraries = ""

        if len(top) > 1:
            libraries[top[0]] = []
            top_libraries = library_options.format(lib=top[0])

        top_unit = top[-1]

        unused_files = []
        for f in self.files:
            if f["file_type"] in _vhdltypes:
                # Files without a specified library will by added to
                # libraries[None] which is perhaps poor form but avoids
                # conflicts with user generated names
                libraries[f["logical_name"]] = libraries.get(f["logical_name"], []) + [
                    f["name"]
                ]
                vhdl_sources += " {file}".format(file=f["name"])
                depfiles.append(f)
            else:
                unused_files.append(f)

        self.edam = edam.copy()
        self.edam["files"] = unused_files

        ghdlimport = ""
        make_libraries_directories = ""

        for lib, files in libraries.items():
            lib_opts = ""
            if lib:
                analyze_options += " -P./{}".format(lib)
                make_libraries_directories += "\tmkdir -p {}\n".format(lib)
                lib_opts = library_options.format(lib=lib)
            ghdlimport += "\tghdl -i $(STD) $(ANALYZE_OPTIONS) {} {}\n".format(
                lib_opts, " ".join(files)
            )

        commands = EdaCommands()
        if self.tool_options.get("mode") == "verilog":
            commands.add(
                ["ghdl", "-a"] + stdarg + analyze_options + [top_libraries, top_unit],
                # FIXME: Get names of object files here
                [f"work-obj{stdarg[0]}.cf"],
                depfiles,
            )
Exemple #17
0
    def configure(self, edam):
        super().configure(edam)

        # Future improvement: Separate include directories of c and verilog files
        incdirs = set()

        verilator_file = self.name + ".vc"

        vc = []
        vc.append("--Mdir .")

        modes = ["sc", "cc", "lint-only"]

        # Default to cc mode if not specified
        mode = self.tool_options.get("mode", "cc")

        if not mode in modes:
            _s = "Illegal verilator mode {}. Allowed values are {}"
            raise RuntimeError(_s.format(mode, ", ".join(modes)))
        vc.append("--" + mode)

        vc += self.tool_options.get("verilator_options", [])

        for include_dir in incdirs:
            vc.append(f"+incdir+" + include_dir)
            vc.append("-CFLAGS -I" + include_dir)

        vlt_files = []
        vlog_files = []
        opt_c_files = []
        uhdm_files = []

        unused_files = []
        depfiles = []
        for f in self.files:
            file_type = f.get("file_type", "")
            depfile = True
            if file_type.startswith("systemVerilogSource"
                                    ) or file_type.startswith("verilogSource"):
                if not self._add_include_dir(f, incdirs):
                    vlog_files.append(f["name"])
            elif file_type in ["cppSource", "systemCSource", "cSource"]:
                if not self._add_include_dir(f, incdirs):
                    opt_c_files.append(f["name"])
            elif file_type == "vlt":
                vlt_files.append(f["name"])
            elif file_type == "uhdm":
                uhdm_files.append(f["name"])
            else:
                unused_files.append(f)
                depfile = False

            if depfile:
                depfiles.append(f["name"])

        # Add created exe/.so/.a to EDAM output files?
        self.edam = edam.copy()
        self.edam["files"] = unused_files

        if uhdm_files:
            vc.append("--uhdm-ast-sv")

        vc += vlt_files + uhdm_files + vlog_files

        vc.append(f"--top-module {self.toplevel}\n")
        if str(self.tool_options.get("exe")).lower() != "false":
            vc.append("--exe")

        vc += opt_c_files

        for k, v in self.vlogparam.items():
            vc.append("-G{}={}".format(
                k, self._param_value_str(v, str_quote_style='\\"')))
        for k, v in self.vlogdefine.items():
            vc.append("-D{}={}\n".format(k, self._param_value_str(v)))

        with open(os.path.join(self.work_root, verilator_file), "w") as ffile:
            ffile.write("\n".join(vc) + "\n")

        mk_file = f"V{self.toplevel}.mk"
        exe_file = f"V{self.toplevel}"
        commands = EdaCommands()
        commands.add(
            ["verilator", "-f", verilator_file],
            [mk_file],
            depfiles,
        )

        if mode == "lint-only":
            self.default_target = mk_file
        else:
            commands.add(
                ["make", "-f", mk_file] +
                self.tool_options.get("make_options", []),
                [exe_file],
                [mk_file],
            )
            self.default_target = exe_file

        self.commands = commands.commands