From: git Date: Sun, 12 Apr 2026 12:37:03 +0000 (-0400) Subject: initial public commit X-Git-Url: https://git.datadissipation.net/?a=commitdiff_plain;h=f068af3271ed10b485b0f7592d1f4ad478c1262b;p=wsl-litex-quartus.git initial public commit --- f068af3271ed10b485b0f7592d1f4ad478c1262b diff --git a/README.md b/README.md new file mode 100644 index 0000000..512f422 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +A patch to integrate Quartus Prime installed on Windows into WSL LiteX workflow. + +Tested on WSL2. + +###Installation + +If you are in the same directory as the patch file: + +``` +cd +patch -p1 < "$OLDPWD"/wsl-litex-quartus.diff +``` + +If LiteX was installed with Python venv, `` is `/litex`. +Before installling, you might want to change the fallback for `$LITEX_WIN32_QUARTUS_PATH` in the patch file so you +don't have to set it on each new session (or just export the variable in venv activation script). + +###Environment Variables + +* `$WSL_DISTRO_NAME` - is used to set the path to files for Quartus, ensure it is correct (should be set automatically) + +* `$LITEX_WIN32_QUARTUS_PATH` - is the path to Quartus `bin64` from within WSL, eg., `/mnt/c/altera_lite/25.1std/quartus/bin64` + +###Flags + +* `--win32-quartus` - use the Windows Quartus install + +* `--win32-quartus-path WIN32_QUARTUS_PATH` - path to Quartus, overrides `$LITEX_WIN32_QUARTUS_PATH` diff --git a/wsl-litex-quartus.diff b/wsl-litex-quartus.diff new file mode 100644 index 0000000..8ae3e4d --- /dev/null +++ b/wsl-litex-quartus.diff @@ -0,0 +1,230 @@ +diff --git a/litex/build/altera/programmer.py b/litex/build/altera/programmer.py +index c797c564f..e25af5565 100644 +--- a/litex/build/altera/programmer.py ++++ b/litex/build/altera/programmer.py +@@ -4,20 +4,49 @@ + # Copyright (c) 2015-2018 Florent Kermarrec + # SPDX-License-Identifier: BSD-2-Clause + ++import argparse + from litex.build.generic_programmer import GenericProgrammer ++from litex.build.altera import quartus ++from litex.build import tools ++ ++_toolchain_args = None ++ ++# called by quartus.py for win32 quartus args ++def set_toolchain_args(args_dict): ++ global _toolchain_args ++ _toolchain_args = args_dict ++ ++def get_toolchain_args(): ++ global _toolchain_args ++ if _toolchain_args is None: ++ parser = argparse.ArgumentParser(add_help=False) ++ quartus.fill_args(parser) ++ args, _ = parser.parse_known_args() ++ _toolchain_args = quartus.get_argdict(args) ++ return _toolchain_args + + # USBBlaster --------------------------------------------------------------------------------------- + + class USBBlaster(GenericProgrammer): + needs_bitreverse = False + +- def __init__(self, cable_name="USB-Blaster", device_id=1): ++ def __init__(self, prog_name="quartus_pgm", cable_name="USB-Blaster", device_id=1): ++ self.prog_name = prog_name + self.cable_name = cable_name + self.device_id = device_id + ++ args = get_toolchain_args() ++ self.win32_quartus = args["win32_quartus"] ++ self.quartus_path = args["quartus_path"] ++ self.wsl_path = args["wsl_path"] ++ + def load_bitstream(self, bitstream_file, cable_suffix=""): +- self.call(["quartus_pgm", ++ if self.win32_quartus: ++ self.prog_name = f"{self.quartus_path}{self.prog_name}.exe" ++ bitstream_file = f"{self.wsl_path}{bitstream_file}" ++ ++ self.call([self.prog_name, + "-m", "jtag", +- "-c", "{}{}".format(self.cable_name, cable_suffix), +- "-o", "p;{}@{}".format(bitstream_file, self.device_id) ++ "-c", f"{self.cable_name}{cable_suffix}" ++ "-o", f"p;{bitstream_file}@{self.device_id}" + ]) +diff --git a/litex/build/altera/quartus.py b/litex/build/altera/quartus.py +index 786e89f3c..38b1b3932 100644 +--- a/litex/build/altera/quartus.py ++++ b/litex/build/altera/quartus.py +@@ -18,6 +18,7 @@ from migen.fhdl.simplify import FullMemoryWE + + from litex.build.generic_platform import Pins, IOStandard, Misc + from litex.build.generic_toolchain import GenericToolchain ++from litex.build.altera import programmer + from litex.build import tools + + # AlteraQuartusToolchain --------------------------------------------------------------------------- +@@ -32,19 +33,29 @@ class AlteraQuartusToolchain(GenericToolchain): + super().__init__() + self._synth_tool = "quartus_map" + self._conv_tool = "quartus_cpf" ++ self.win32_quartus = False ++ self.win32_quartus_path = "" + self.clock_constraints = [] + self.additional_sdc_commands = [] + self.additional_qsf_commands = [] + self.cst = [] + + def build(self, platform, fragment, +- synth_tool = "quartus_map", +- conv_tool = "quartus_cpf", ++ synth_tool = "quartus_map", ++ conv_tool = "quartus_cpf", ++ win32_quartus = False, ++ win32_quartus_path = "", ++ quartus_path = "", ++ wsl_path = "", + **kwargs): + +- self._synth_tool = synth_tool +- self._conv_tool = conv_tool ++ self._synth_tool = synth_tool ++ self._conv_tool = conv_tool + ++ self.win32_quartus = win32_quartus ++ self.quartus_path = quartus_path ++ self.wsl_path = wsl_path ++ + if not platform.device.startswith("10M"): + # Apply FullMemoryWE on Design (Quartus does not infer memories correctly otherwise). + FullMemoryWE()(fragment) +@@ -152,10 +163,10 @@ class AlteraQuartusToolchain(GenericToolchain): + # Add sources + for filename, language, library, *copy in self.platform.sources: + if language == "verilog": language = "systemverilog" # Enforce use of SystemVerilog +- tpl = "set_global_assignment -name {lang}_FILE {path} -library {lib}" ++ tpl = "set_global_assignment -name {lang}_FILE \"{wsl_path}{path}\" -library {lib}" + # Do not add None type files + if language is not None: +- qsf.append(tpl.format(lang=language.upper(), path=filename.replace("\\", "/"), lib=library)) ++ qsf.append(tpl.format(lang=language.upper(), wsl_path=self.wsl_path, path=filename.replace("\\", "/"), lib=library)) + # Check if the file is a header. Those should not be explicitly added to qsf, + # but rather included in include search_path + else: +@@ -167,11 +178,11 @@ class AlteraQuartusToolchain(GenericToolchain): + # Add IPs + for filename in self.platform.ips: + file_ext = os.path.splitext(filename)[1][1:].upper() +- qsf.append(f"set_global_assignment -name {file_ext}_FILE " + filename.replace("\\", "/")) ++ qsf.append(f"set_global_assignment -name {file_ext}_FILE \"{self.wsl_path}" + filename.replace("\\", "/")) + "\"" + + # Add include paths + for path in self.platform.verilog_include_paths: +- qsf.append("set_global_assignment -name SEARCH_PATH {}".format(path.replace("\\", "/"))) ++ qsf.append("set_global_assignment -name SEARCH_PATH \"{}{}\"".format(self.wsl_path, path.replace("\\", "/"))) + + # Set top level + qsf.append("set_global_assignment -name top_level_entity " + self._build_name) +@@ -195,6 +206,9 @@ class AlteraQuartusToolchain(GenericToolchain): + + def build_script(self): + build_name = self._build_name ++ wsl_ext = "" ++ if self.win32_quartus: ++ wsl_ext = ".exe" + + if sys.platform in ["win32", "cygwin"]: + script_file = "build_" + build_name + ".bat" +@@ -205,10 +219,10 @@ class AlteraQuartusToolchain(GenericToolchain): + script_contents += "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\n" + script_contents += "set -e -u -x -o pipefail\n" + script_contents += """ +-{synth_tool} --read_settings_files=on --write_settings_files=off {build_name} -c {build_name} +-quartus_fit --read_settings_files=off --write_settings_files=off {build_name} -c {build_name} +-quartus_asm --read_settings_files=off --write_settings_files=off {build_name} -c {build_name} +-quartus_sta {build_name} -c {build_name}""" ++{quartus_path}{synth_tool}{wsl_ext} --read_settings_files=on --write_settings_files=off {build_name} -c {build_name} ++{quartus_path}quartus_fit{wsl_ext} --read_settings_files=off --write_settings_files=off {build_name} -c {build_name} ++{quartus_path}quartus_asm{wsl_ext} --read_settings_files=off --write_settings_files=off {build_name} -c {build_name} ++{quartus_path}quartus_sta{wsl_ext} {build_name} -c {build_name}""" + + # Create .rbf. + if self.platform.create_rbf: +@@ -222,7 +236,7 @@ if exist "{build_name}.sof" ( + script_contents += """ + if [ -f "{build_name}.sof" ] + then +- {conv_tool} -c {build_name}.sof {build_name}.rbf ++ {quartus_path}{conv_tool}{wsl_ext} -c {build_name}.sof {build_name}.rbf + fi + """ + # Create .svf. +@@ -237,10 +251,10 @@ if exist "{build_name}.sof" ( + script_contents += """ + if [ -f "{build_name}.sof" ] + then +- {conv_tool} -c -q \"12.0MHz\" -g 3.3 -n p {build_name}.sof {build_name}.svf ++ {quartus_path}{conv_tool}{wsl_ext} -c -q \"12.0MHz\" -g 3.3 -n p {build_name}.sof {build_name}.svf + fi + """ +- script_contents = script_contents.format(build_name=build_name, synth_tool=self._synth_tool, conv_tool=self._conv_tool) ++ script_contents = script_contents.format(build_name=build_name, quartus_path=self.quartus_path, wsl_ext=wsl_ext, synth_tool=self._synth_tool, conv_tool=self._conv_tool) + tools.write_to_file(script_file, script_contents, force_unix=True) + + return script_file +@@ -251,21 +265,45 @@ fi + else: + shell = ["bash"] + +- if which(self._synth_tool) is None: ++ if which(self._synth_tool) is None and not self.win32_quartus: + msg = "Unable to find Quartus toolchain, please:\n" + msg += "- Add Quartus toolchain to your $PATH." + raise OSError(msg) + ++ testpath = "{}{}.exe".format(self.quartus_path, self._synth_tool) ++ if self.win32_quartus and not os.path.isfile(testpath): ++ msg = "Unable to find Quartus toolchain, please:\n" ++ msg += "- set $LITEX_WIN32_QUARTUS_PATH with the path accessible from within WSL\n" ++ msg += "- or use \"--win32-quartus-path\" flag to set the path" ++ raise OSError(msg) ++ + if subprocess.call(shell + [script]) != 0: + raise OSError("Error occured during Quartus's script execution.") + + def fill_args(parser): + toolchain_group = parser.add_argument_group(title="Quartus toolchain options") +- toolchain_group.add_argument("--synth-tool", default="quartus_map", help="Synthesis mode (quartus_map or quartus_syn).") +- toolchain_group.add_argument("--conv-tool", default="quartus_cpf", help="Quartus Prime Convert_programming_file (quartus_cpf or quartus_pfg).") ++ toolchain_group.add_argument("--synth-tool", default="quartus_map", help="Synthesis mode (quartus_map or quartus_syn).") ++ toolchain_group.add_argument("--conv-tool", default="quartus_cpf", help="Quartus Prime Convert_programming_file (quartus_cpf or quartus_pfg).") ++ toolchain_group.add_argument("--win32-quartus", action="store_true", help="Use the Windows install of Quartus.") ++ toolchain_group.add_argument("--win32-quartus-path", default="", help="Path to the Windows install of Quartus.") + + def get_argdict(args): +- return { +- "synth_tool" : args.synth_tool, +- "conv_tool" : args.conv_tool, ++ if args.win32_quartus: ++ if args.win32_quartus_path: ++ quartus_path = args.win32_quartus_path ++ else: ++ quartus_path = os.getenv("LITEX_WIN32_QUARTUS_PATH", "/mnt/c/altera_lite/25.1std/quartus/bin64") ++ ++ quartus_path += "/" # Double slash is OK ++ ++ args_dict = { ++ "synth_tool" : args.synth_tool, ++ "conv_tool" : args.conv_tool, ++ "win32_quartus" : args.win32_quartus, ++ "win32_quartus_path" : args.win32_quartus_path, ++ "quartus_path" : quartus_path, ++ "wsl_path" : f"//wsl.localhost/{os.getenv("WSL_DISTRO_NAME", "")}", + } ++ ++ programmer.set_toolchain_args(args_dict) ++ return args_dict