1 diff --git a/litex/build/altera/programmer.py b/litex/build/altera/programmer.py
2 index c797c564f..9056cbef9 100644
3 --- a/litex/build/altera/programmer.py
4 +++ b/litex/build/altera/programmer.py
6 # Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
7 # SPDX-License-Identifier: BSD-2-Clause
10 from litex.build.generic_programmer import GenericProgrammer
11 +from litex.build.altera import quartus
12 +from litex.build import tools
14 +_toolchain_args = None
16 +# called by quartus.py for win32 quartus args
17 +def set_toolchain_args(args_dict):
18 + global _toolchain_args
19 + _toolchain_args = args_dict
21 +def get_toolchain_args():
22 + global _toolchain_args
23 + if _toolchain_args is None:
24 + parser = argparse.ArgumentParser(add_help=False)
25 + quartus.fill_args(parser)
26 + args, _ = parser.parse_known_args()
27 + _toolchain_args = quartus.get_argdict(args)
28 + return _toolchain_args
30 # USBBlaster ---------------------------------------------------------------------------------------
32 class USBBlaster(GenericProgrammer):
33 needs_bitreverse = False
35 - def __init__(self, cable_name="USB-Blaster", device_id=1):
36 + def __init__(self, prog_name="quartus_pgm", cable_name="USB-Blaster", device_id=1):
37 + self.prog_name = prog_name
38 self.cable_name = cable_name
39 self.device_id = device_id
41 + args = get_toolchain_args()
42 + self.win32_quartus = args["win32_quartus"]
43 + self.quartus_path = args["quartus_path"]
44 + self.wsl_path = args["wsl_path"]
46 def load_bitstream(self, bitstream_file, cable_suffix=""):
47 - self.call(["quartus_pgm",
48 + if self.win32_quartus:
49 + self.prog_name = f"{self.quartus_path}{self.prog_name}.exe"
50 + bitstream_file = f"{self.wsl_path}{bitstream_file}"
52 + self.call([self.prog_name,
54 - "-c", "{}{}".format(self.cable_name, cable_suffix),
55 - "-o", "p;{}@{}".format(bitstream_file, self.device_id)
56 + "-c", f"{self.cable_name}{cable_suffix}",
57 + "-o", f"P;{bitstream_file}@{self.device_id}",
59 diff --git a/litex/build/altera/quartus.py b/litex/build/altera/quartus.py
60 index 786e89f3c..c14be3bdd 100644
61 --- a/litex/build/altera/quartus.py
62 +++ b/litex/build/altera/quartus.py
63 @@ -18,6 +18,7 @@ from migen.fhdl.simplify import FullMemoryWE
65 from litex.build.generic_platform import Pins, IOStandard, Misc
66 from litex.build.generic_toolchain import GenericToolchain
67 +from litex.build.altera import programmer
68 from litex.build import tools
70 # AlteraQuartusToolchain ---------------------------------------------------------------------------
71 @@ -32,19 +33,29 @@ class AlteraQuartusToolchain(GenericToolchain):
73 self._synth_tool = "quartus_map"
74 self._conv_tool = "quartus_cpf"
75 + self.win32_quartus = False
76 + self.win32_quartus_path = ""
77 self.clock_constraints = []
78 self.additional_sdc_commands = []
79 self.additional_qsf_commands = []
82 def build(self, platform, fragment,
83 - synth_tool = "quartus_map",
84 - conv_tool = "quartus_cpf",
85 + synth_tool = "quartus_map",
86 + conv_tool = "quartus_cpf",
87 + win32_quartus = False,
88 + win32_quartus_path = "",
93 - self._synth_tool = synth_tool
94 - self._conv_tool = conv_tool
95 + self._synth_tool = synth_tool
96 + self._conv_tool = conv_tool
98 + self.win32_quartus = win32_quartus
99 + self.quartus_path = quartus_path
100 + self.wsl_path = wsl_path
102 if not platform.device.startswith("10M"):
103 # Apply FullMemoryWE on Design (Quartus does not infer memories correctly otherwise).
104 FullMemoryWE()(fragment)
105 @@ -152,10 +163,10 @@ class AlteraQuartusToolchain(GenericToolchain):
107 for filename, language, library, *copy in self.platform.sources:
108 if language == "verilog": language = "systemverilog" # Enforce use of SystemVerilog
109 - tpl = "set_global_assignment -name {lang}_FILE {path} -library {lib}"
110 + tpl = "set_global_assignment -name {lang}_FILE \"{wsl_path}{path}\" -library {lib}"
111 # Do not add None type files
112 if language is not None:
113 - qsf.append(tpl.format(lang=language.upper(), path=filename.replace("\\", "/"), lib=library))
114 + qsf.append(tpl.format(lang=language.upper(), wsl_path=self.wsl_path, path=filename.replace("\\", "/"), lib=library))
115 # Check if the file is a header. Those should not be explicitly added to qsf,
116 # but rather included in include search_path
118 @@ -167,11 +178,11 @@ class AlteraQuartusToolchain(GenericToolchain):
120 for filename in self.platform.ips:
121 file_ext = os.path.splitext(filename)[1][1:].upper()
122 - qsf.append(f"set_global_assignment -name {file_ext}_FILE " + filename.replace("\\", "/"))
123 + qsf.append(f"set_global_assignment -name {file_ext}_FILE \"{self.wsl_path}" + filename.replace("\\", "/")) + "\""
126 for path in self.platform.verilog_include_paths:
127 - qsf.append("set_global_assignment -name SEARCH_PATH {}".format(path.replace("\\", "/")))
128 + qsf.append("set_global_assignment -name SEARCH_PATH \"{}{}\"".format(self.wsl_path, path.replace("\\", "/")))
131 qsf.append("set_global_assignment -name top_level_entity " + self._build_name)
132 @@ -195,6 +206,9 @@ class AlteraQuartusToolchain(GenericToolchain):
134 def build_script(self):
135 build_name = self._build_name
137 + if self.win32_quartus:
140 if sys.platform in ["win32", "cygwin"]:
141 script_file = "build_" + build_name + ".bat"
142 @@ -205,10 +219,10 @@ class AlteraQuartusToolchain(GenericToolchain):
143 script_contents += "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\n"
144 script_contents += "set -e -u -x -o pipefail\n"
145 script_contents += """
146 -{synth_tool} --read_settings_files=on --write_settings_files=off {build_name} -c {build_name}
147 -quartus_fit --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
148 -quartus_asm --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
149 -quartus_sta {build_name} -c {build_name}"""
150 +{quartus_path}{synth_tool}{wsl_ext} --read_settings_files=on --write_settings_files=off {build_name} -c {build_name}
151 +{quartus_path}quartus_fit{wsl_ext} --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
152 +{quartus_path}quartus_asm{wsl_ext} --read_settings_files=off --write_settings_files=off {build_name} -c {build_name}
153 +{quartus_path}quartus_sta{wsl_ext} {build_name} -c {build_name}"""
156 if self.platform.create_rbf:
157 @@ -222,7 +236,7 @@ if exist "{build_name}.sof" (
158 script_contents += """
159 if [ -f "{build_name}.sof" ]
161 - {conv_tool} -c {build_name}.sof {build_name}.rbf
162 + {quartus_path}{conv_tool}{wsl_ext} -c {build_name}.sof {build_name}.rbf
166 @@ -237,10 +251,10 @@ if exist "{build_name}.sof" (
167 script_contents += """
168 if [ -f "{build_name}.sof" ]
170 - {conv_tool} -c -q \"12.0MHz\" -g 3.3 -n p {build_name}.sof {build_name}.svf
171 + {quartus_path}{conv_tool}{wsl_ext} -c -q \"12.0MHz\" -g 3.3 -n p {build_name}.sof {build_name}.svf
174 - script_contents = script_contents.format(build_name=build_name, synth_tool=self._synth_tool, conv_tool=self._conv_tool)
175 + 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)
176 tools.write_to_file(script_file, script_contents, force_unix=True)
179 @@ -251,21 +265,47 @@ fi
183 - if which(self._synth_tool) is None:
184 + if which(self._synth_tool) is None and not self.win32_quartus:
185 msg = "Unable to find Quartus toolchain, please:\n"
186 msg += "- Add Quartus toolchain to your $PATH."
189 + testpath = "{}{}.exe".format(self.quartus_path, self._synth_tool)
190 + if self.win32_quartus and not os.path.isfile(testpath):
191 + msg = "Unable to find Quartus toolchain, please:\n"
192 + msg += "- set $LITEX_WIN32_QUARTUS_PATH with the path accessible from within WSL\n"
193 + msg += "- or use \"--win32-quartus-path\" flag to set the path"
196 if subprocess.call(shell + [script]) != 0:
197 raise OSError("Error occured during Quartus's script execution.")
199 def fill_args(parser):
200 toolchain_group = parser.add_argument_group(title="Quartus toolchain options")
201 - toolchain_group.add_argument("--synth-tool", default="quartus_map", help="Synthesis mode (quartus_map or quartus_syn).")
202 - toolchain_group.add_argument("--conv-tool", default="quartus_cpf", help="Quartus Prime Convert_programming_file (quartus_cpf or quartus_pfg).")
203 + toolchain_group.add_argument("--synth-tool", default="quartus_map", help="Synthesis mode (quartus_map or quartus_syn).")
204 + toolchain_group.add_argument("--conv-tool", default="quartus_cpf", help="Quartus Prime Convert_programming_file (quartus_cpf or quartus_pfg).")
205 + toolchain_group.add_argument("--win32-quartus", action="store_true", help="Use the Windows install of Quartus.")
206 + toolchain_group.add_argument("--win32-quartus-path", default="", help="Path to the Windows install of Quartus.")
208 def get_argdict(args):
210 - "synth_tool" : args.synth_tool,
211 - "conv_tool" : args.conv_tool,
214 + if args.win32_quartus:
215 + if args.win32_quartus_path:
216 + quartus_path = args.win32_quartus_path
218 + quartus_path = os.getenv("LITEX_WIN32_QUARTUS_PATH", "/mnt/c/altera_lite/25.1std/quartus/bin64")
219 + quartus_path += "/" # Double slash is OK
220 + wsl_path = f"//wsl.localhost/{os.getenv("WSL_DISTRO_NAME", "")}"
223 + "synth_tool" : args.synth_tool,
224 + "conv_tool" : args.conv_tool,
225 + "win32_quartus" : args.win32_quartus,
226 + "win32_quartus_path" : args.win32_quartus_path,
227 + "quartus_path" : quartus_path,
228 + "wsl_path" : wsl_path,
231 + programmer.set_toolchain_args(args_dict)