]> datadissipation.net git - wsl-litex-quartus.git/commitdiff
initial public commit
authorgit <redacted>
Sun, 12 Apr 2026 12:37:03 +0000 (08:37 -0400)
committergit <redacted>
Sun, 12 Apr 2026 12:37:03 +0000 (08:37 -0400)
README.md [new file with mode: 0644]
wsl-litex-quartus.diff [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
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 <path-to-your-litex-install>
+patch -p1 < "$OLDPWD"/wsl-litex-quartus.diff
+```
+
+If LiteX was installed with Python venv, `<path-to-your-litex-install>` is `<directory-with-litex_setup.py>/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 (file)
index 0000000..8ae3e4d
--- /dev/null
@@ -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 <florent@enjoy-digital.fr>
+ # 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