opencos-eda 0.3.10__py3-none-any.whl → 0.3.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opencos/commands/deps_help.py +63 -113
- opencos/commands/export.py +7 -2
- opencos/commands/multi.py +3 -3
- opencos/commands/sim.py +14 -15
- opencos/commands/synth.py +1 -2
- opencos/commands/upload.py +192 -4
- opencos/commands/waves.py +8 -8
- opencos/deps/deps_commands.py +6 -6
- opencos/deps/deps_processor.py +129 -50
- opencos/docs/Architecture.md +45 -0
- opencos/docs/ConnectingApps.md +29 -0
- opencos/docs/DEPS.md +199 -0
- opencos/docs/Debug.md +77 -0
- opencos/docs/DirectoryStructure.md +22 -0
- opencos/docs/Installation.md +117 -0
- opencos/docs/OcVivadoTcl.md +63 -0
- opencos/docs/OpenQuestions.md +7 -0
- opencos/docs/README.md +13 -0
- opencos/docs/RtlCodingStyle.md +54 -0
- opencos/docs/eda.md +147 -0
- opencos/docs/oc_cli.md +135 -0
- opencos/eda.py +132 -35
- opencos/eda_base.py +173 -47
- opencos/eda_config.py +56 -17
- opencos/eda_config_defaults.yml +21 -4
- opencos/files.py +26 -1
- opencos/tools/cocotb.py +5 -5
- opencos/tools/invio.py +2 -2
- opencos/tools/invio_yosys.py +2 -1
- opencos/tools/iverilog.py +3 -3
- opencos/tools/quartus.py +113 -115
- opencos/tools/questa_common.py +2 -2
- opencos/tools/riviera.py +3 -3
- opencos/tools/slang.py +11 -7
- opencos/tools/slang_yosys.py +1 -0
- opencos/tools/surelog.py +4 -3
- opencos/tools/verilator.py +4 -4
- opencos/tools/vivado.py +307 -176
- opencos/tools/yosys.py +4 -4
- opencos/util.py +6 -3
- opencos/utils/dict_helpers.py +31 -0
- opencos/utils/markup_helpers.py +2 -2
- opencos/utils/subprocess_helpers.py +3 -3
- opencos/utils/vscode_helper.py +2 -2
- opencos/utils/vsim_helper.py +16 -5
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.11.dist-info}/METADATA +1 -1
- opencos_eda-0.3.11.dist-info/RECORD +94 -0
- opencos_eda-0.3.10.dist-info/RECORD +0 -81
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.11.dist-info}/WHEEL +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.11.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.11.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.11.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.11.dist-info}/top_level.txt +0 -0
opencos/tools/quartus.py
CHANGED
|
@@ -9,16 +9,14 @@ Used for Intel FPGA synthesis, place & route, and bitstream generation.
|
|
|
9
9
|
import os
|
|
10
10
|
import re
|
|
11
11
|
import shlex
|
|
12
|
-
import shutil
|
|
13
12
|
import subprocess
|
|
14
|
-
|
|
15
13
|
from pathlib import Path
|
|
16
14
|
|
|
17
|
-
from opencos import util
|
|
18
|
-
from opencos.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
from opencos import util
|
|
16
|
+
from opencos.commands import CommandSynth, CommandBuild, CommandFList, CommandProj, \
|
|
17
|
+
CommandUpload, CommandOpen
|
|
18
|
+
from opencos.eda_base import Tool, get_eda_exec
|
|
19
|
+
from opencos.files import safe_shutil_which
|
|
22
20
|
from opencos.utils.str_helpers import sanitize_defines_for_sh, strip_outer_quotes
|
|
23
21
|
|
|
24
22
|
class ToolQuartus(Tool):
|
|
@@ -48,16 +46,17 @@ class ToolQuartus(Tool):
|
|
|
48
46
|
if self._VERSION:
|
|
49
47
|
return self._VERSION
|
|
50
48
|
|
|
51
|
-
path =
|
|
49
|
+
path = safe_shutil_which(self._EXE)
|
|
52
50
|
if not path:
|
|
53
51
|
self.error("Quartus not in path, need to install or add to $PATH",
|
|
54
52
|
f"(looked for '{self._EXE}')")
|
|
55
53
|
else:
|
|
56
54
|
self.quartus_exe = path
|
|
57
55
|
self.quartus_base_path, _ = os.path.split(path)
|
|
58
|
-
self.quartus_gui_exe = shutil.which('quartus') # vs quartus_sh
|
|
59
|
-
|
|
60
56
|
|
|
57
|
+
self.quartus_gui_exe = safe_shutil_which(
|
|
58
|
+
os.path.join(self.quartus_base_path, 'quartus') # vs quartus_sh
|
|
59
|
+
)
|
|
61
60
|
|
|
62
61
|
# Get version based on install path name or by running quartus_sh --version
|
|
63
62
|
util.debug(f"quartus path = {self.quartus_exe}")
|
|
@@ -151,7 +150,6 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
151
150
|
self.write_tcl_file(tcl_file=tcl_file)
|
|
152
151
|
|
|
153
152
|
# execute Quartus synthesis
|
|
154
|
-
command_list_gui = [self.quartus_gui_exe, '-t', tcl_file]
|
|
155
153
|
command_list = [
|
|
156
154
|
self.quartus_exe, '-t', tcl_file
|
|
157
155
|
]
|
|
@@ -172,11 +170,7 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
172
170
|
typ='text', description='Quartus Synthesis Report'
|
|
173
171
|
)
|
|
174
172
|
|
|
175
|
-
|
|
176
|
-
self.exec(self.args['work-dir'], command_list_gui)
|
|
177
|
-
else:
|
|
178
|
-
self.exec(self.args['work-dir'], command_list)
|
|
179
|
-
|
|
173
|
+
self.exec(self.args['work-dir'], command_list)
|
|
180
174
|
|
|
181
175
|
saved_qpf_filename = self.args["top"] + '.qpf'
|
|
182
176
|
if not os.path.isfile(os.path.join(self.args['work-dir'], saved_qpf_filename)):
|
|
@@ -185,8 +179,13 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
185
179
|
|
|
186
180
|
util.info(f"Synthesis done, results are in: {self.args['work-dir']}")
|
|
187
181
|
|
|
188
|
-
# Note: in GUI mode, if
|
|
189
|
-
#
|
|
182
|
+
# Note: in GUI mode, if we were to run:
|
|
183
|
+
# ran: quaruts -t build.tcl
|
|
184
|
+
# it treats the tcl script as running "headless" as a pre-script, and won't open the
|
|
185
|
+
# GUI anyway, and will exit on completion,
|
|
186
|
+
# Instead we:
|
|
187
|
+
# 1. always run with quartus_sh, so text goes to stdout
|
|
188
|
+
# 2. we'll re-open the project in GUI mode, here:
|
|
190
189
|
if self.args['gui'] and self.quartus_gui_exe:
|
|
191
190
|
self.exec(
|
|
192
191
|
work_dir=self.args['work-dir'],
|
|
@@ -212,19 +211,22 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
212
211
|
# Add source files (convert to relative paths and use forward slashes)
|
|
213
212
|
# Note that default of self.args['all-sv'] is False so we should have added
|
|
214
213
|
# all files to self.files_sv instead of files_v:
|
|
214
|
+
# Note that tcl uses POSIX paths, so \\ -> /
|
|
215
215
|
for f in self.files_v:
|
|
216
|
-
rel_path = os.path.relpath(f, self.args['work-dir']).
|
|
216
|
+
rel_path = Path(os.path.relpath(f, self.args['work-dir'])).as_posix()
|
|
217
217
|
tcl_lines.append(f"set_global_assignment -name VERILOG_FILE \"{rel_path}\"")
|
|
218
218
|
for f in self.files_sv:
|
|
219
|
-
rel_path = os.path.relpath(f, self.args['work-dir']).
|
|
219
|
+
rel_path = Path(os.path.relpath(f, self.args['work-dir'])).as_posix()
|
|
220
220
|
tcl_lines.append(f"set_global_assignment -name SYSTEMVERILOG_FILE \"{rel_path}\"")
|
|
221
221
|
for f in self.files_vhd:
|
|
222
|
-
rel_path = os.path.relpath(f, self.args['work-dir']).
|
|
222
|
+
rel_path = Path(os.path.relpath(f, self.args['work-dir'])).as_posix()
|
|
223
223
|
tcl_lines.append(f"set_global_assignment -name VHDL_FILE \"{rel_path}\"")
|
|
224
224
|
|
|
225
225
|
# Add include directories - Quartus needs the base directory where "lib/" can be found
|
|
226
226
|
for incdir in self.incdirs:
|
|
227
|
-
tcl_lines.append(
|
|
227
|
+
tcl_lines.append(
|
|
228
|
+
f"set_global_assignment -name SEARCH_PATH \"{Path(incdir).as_posix()}\""
|
|
229
|
+
)
|
|
228
230
|
|
|
229
231
|
# Parameters --> set_parameter -name <Parameter_Name> <Value>
|
|
230
232
|
for k,v in self.parameters.items():
|
|
@@ -242,7 +244,7 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
242
244
|
for incdir in self.incdirs:
|
|
243
245
|
if os.path.exists(incdir):
|
|
244
246
|
tcl_lines.append(
|
|
245
|
-
f"set_global_assignment -name USER_LIBRARIES \"{incdir}\""
|
|
247
|
+
f"set_global_assignment -name USER_LIBRARIES \"{Path(incdir).as_posix()}\""
|
|
246
248
|
)
|
|
247
249
|
|
|
248
250
|
# Add defines
|
|
@@ -268,7 +270,7 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
268
270
|
for f in sdc_files:
|
|
269
271
|
for attr in ('SDC_FILE', 'SYN_SDC_FILE', 'RTL_SDC_FILE'):
|
|
270
272
|
tcl_lines.extend([
|
|
271
|
-
f"set_global_assignment -name {attr} \"{f}\""
|
|
273
|
+
f"set_global_assignment -name {attr} \"{Path(f).as_posix()}\""
|
|
272
274
|
])
|
|
273
275
|
tcl_lines.append("set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON")
|
|
274
276
|
|
|
@@ -331,7 +333,7 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
331
333
|
f"design={self.args['design']}")
|
|
332
334
|
|
|
333
335
|
command_list = [
|
|
334
|
-
|
|
336
|
+
get_eda_exec('flist'), 'flist',
|
|
335
337
|
'--no-default-log',
|
|
336
338
|
'--tool=' + self.args['tool'],
|
|
337
339
|
'--force',
|
|
@@ -411,7 +413,7 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
411
413
|
fname_abs = os.path.abspath(fname)
|
|
412
414
|
if not os.path.isfile(fname_abs):
|
|
413
415
|
self.error(f'add-tcl-files: "{fname_abs}"; does not exist')
|
|
414
|
-
build_tcl_lines.append(f'source {fname_abs}')
|
|
416
|
+
build_tcl_lines.append(f'source {Path(fname_abs).as_posix()}')
|
|
415
417
|
build_tcl_lines.append('')
|
|
416
418
|
|
|
417
419
|
# If we don't have any args for --flow-tcl-files, then use a default flow:
|
|
@@ -428,7 +430,7 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
428
430
|
fname_abs = os.path.abspath(fname)
|
|
429
431
|
if not os.path.isfile(fname_abs):
|
|
430
432
|
self.error(f'flow-tcl-files: "{fname_abs}"; does not exist')
|
|
431
|
-
build_tcl_lines.append(f'source {fname_abs}')
|
|
433
|
+
build_tcl_lines.append(f'source {Path(fname_abs).as_posix()}')
|
|
432
434
|
build_tcl_lines.append('')
|
|
433
435
|
|
|
434
436
|
with open(build_tcl_file, 'w', encoding='utf-8') as ftcl:
|
|
@@ -552,20 +554,22 @@ class CommandProjQuartus(CommandProj, ToolQuartus):
|
|
|
552
554
|
f"set_global_assignment -name TOP_LEVEL_ENTITY {top}",
|
|
553
555
|
]
|
|
554
556
|
|
|
555
|
-
# Add source files
|
|
557
|
+
# Add source files, tcl prefers POSIX paths even in Windows Powershell.
|
|
556
558
|
for f in self.files_v:
|
|
557
|
-
rel_path = os.path.relpath(f, self.args['work-dir']).
|
|
559
|
+
rel_path = Path(os.path.relpath(f, self.args['work-dir'])).as_posix()
|
|
558
560
|
tcl_lines.append(f"set_global_assignment -name VERILOG_FILE \"{rel_path}\"")
|
|
559
561
|
for f in self.files_sv:
|
|
560
|
-
rel_path = os.path.relpath(f, self.args['work-dir']).
|
|
562
|
+
rel_path = Path(os.path.relpath(f, self.args['work-dir'])).as_posix()
|
|
561
563
|
tcl_lines.append(f"set_global_assignment -name SYSTEMVERILOG_FILE \"{rel_path}\"")
|
|
562
564
|
for f in self.files_vhd:
|
|
563
|
-
rel_path = os.path.relpath(f, self.args['work-dir']).
|
|
565
|
+
rel_path = Path(os.path.relpath(f, self.args['work-dir'])).as_posix()
|
|
564
566
|
tcl_lines.append(f"set_global_assignment -name VHDL_FILE \"{rel_path}\"")
|
|
565
567
|
|
|
566
568
|
# Add include directories
|
|
567
569
|
for incdir in self.incdirs:
|
|
568
|
-
tcl_lines.append(
|
|
570
|
+
tcl_lines.append(
|
|
571
|
+
f"set_global_assignment -name SEARCH_PATH \"{Path(incdir).as_posix()}\""
|
|
572
|
+
)
|
|
569
573
|
|
|
570
574
|
# Add defines
|
|
571
575
|
for key, value in self.defines.items():
|
|
@@ -575,9 +579,10 @@ class CommandProjQuartus(CommandProj, ToolQuartus):
|
|
|
575
579
|
tcl_lines.append(f"set_global_assignment -name VERILOG_MACRO \"{key}={value}\"")
|
|
576
580
|
|
|
577
581
|
# Add constraints if available
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
582
|
+
for sdc_file in self.files_sdc:
|
|
583
|
+
tcl_lines.append(
|
|
584
|
+
f"set_global_assignment -name SDC_FILE \"{Path(sdc_file).as_posix()}\""
|
|
585
|
+
)
|
|
581
586
|
|
|
582
587
|
tcl_lines += [
|
|
583
588
|
"project_close",
|
|
@@ -601,116 +606,109 @@ class CommandProjQuartus(CommandProj, ToolQuartus):
|
|
|
601
606
|
class CommandUploadQuartus(CommandUpload, ToolQuartus):
|
|
602
607
|
'''CommandUploadQuartus is a command handler for: eda upload --tool=quartus'''
|
|
603
608
|
|
|
609
|
+
SUPPORTED_BIT_EXT = ['.sof']
|
|
610
|
+
|
|
604
611
|
def __init__(self, config: dict):
|
|
605
612
|
CommandUpload.__init__(self, config)
|
|
606
613
|
ToolQuartus.__init__(self, config=self.config)
|
|
607
614
|
# add args specific to this tool
|
|
608
615
|
self.args.update({
|
|
609
|
-
'sof-file': "",
|
|
610
616
|
'cable': "1",
|
|
611
617
|
'device': "1",
|
|
612
618
|
'list-cables': False,
|
|
613
619
|
'list-devices': False,
|
|
614
|
-
'list-sof-files': False,
|
|
615
|
-
'tcl-file': "upload.tcl",
|
|
616
|
-
'log-file': "upload.log",
|
|
617
620
|
})
|
|
618
621
|
self.args_help.update({
|
|
619
|
-
'sof-file': 'SOF file to upload (auto-detected if not specified)',
|
|
620
622
|
'cable': 'Cable number to use for programming',
|
|
621
623
|
'device': 'Device number on the cable',
|
|
622
624
|
'list-cables': 'List available programming cables',
|
|
623
625
|
'list-devices': 'List available devices on cable',
|
|
624
|
-
'list-sof-files': 'List available SOF files',
|
|
625
|
-
'tcl-file': 'name of TCL file to be created for upload',
|
|
626
|
-
'log-file': 'log file for upload operation',
|
|
627
626
|
})
|
|
628
627
|
|
|
628
|
+
# Support mulitple arg keys for bitfile and list-bitfiles, so
|
|
629
|
+
# --sof-file and --list-sof-files work the same.
|
|
630
|
+
self.args_args.update({
|
|
631
|
+
'bitfile': ['sof-file'],
|
|
632
|
+
'list-bitfiles': ['list-sof-files'],
|
|
633
|
+
})
|
|
634
|
+
self.args_help.update({
|
|
635
|
+
'bitfile': 'SOF file to upload (auto-detected if not specified)',
|
|
636
|
+
'list-bitfiles': 'List available SOF files',
|
|
637
|
+
})
|
|
638
|
+
|
|
639
|
+
|
|
629
640
|
def do_it(self): # pylint: disable=too-many-branches,too-many-statements,too-many-locals
|
|
641
|
+
'''
|
|
642
|
+
Note this is called directly by opencos.commands.CommandUpload, based
|
|
643
|
+
on which bitfile(s) were found, or if --tool=quartus was set
|
|
644
|
+
|
|
645
|
+
We do not need to handle --list-bitfiles, was handled by CommandUpload.
|
|
646
|
+
'''
|
|
647
|
+
|
|
630
648
|
# add defines for this job
|
|
631
649
|
self.set_tool_defines()
|
|
632
650
|
self.write_eda_config_and_args()
|
|
633
651
|
|
|
652
|
+
# Find quartus_pgm executable, we'll want the one from the same path
|
|
653
|
+
# that was used for our self._EXE (ToolQuartus).
|
|
654
|
+
quartus_pgm = safe_shutil_which(os.path.join(self.quartus_base_path, 'quartus_pgm'))
|
|
655
|
+
if not quartus_pgm:
|
|
656
|
+
self.error("quartus_pgm not found in PATH")
|
|
657
|
+
return
|
|
658
|
+
|
|
659
|
+
# Handle --list-cables
|
|
660
|
+
if self.args['list-cables']:
|
|
661
|
+
util.info("Listing available cables...")
|
|
662
|
+
command_list = [quartus_pgm, '--auto']
|
|
663
|
+
_, stdout, _ = self.exec(self.args['work-dir'], command_list)
|
|
664
|
+
util.info("Available cables listed above")
|
|
665
|
+
return
|
|
666
|
+
|
|
634
667
|
sof_file = None
|
|
635
|
-
if self.args['
|
|
636
|
-
if os.path.isfile(self.args['
|
|
637
|
-
sof_file = self.args['
|
|
638
|
-
|
|
639
|
-
|
|
668
|
+
if self.args['bitfile']:
|
|
669
|
+
if os.path.isfile(self.args['bitfile']):
|
|
670
|
+
sof_file = self.args['bitfile']
|
|
671
|
+
|
|
672
|
+
# self.bitfiles was already set by CommandUpload.process_tokens()
|
|
673
|
+
if len(self.bitfiles) == 1:
|
|
674
|
+
sof_file = self.bitfiles[0]
|
|
640
675
|
|
|
641
676
|
# Auto-discover SOF file if not specified
|
|
642
|
-
if not sof_file
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
elif len(sof_files) > 1:
|
|
655
|
-
if self.args['list-sof-files']:
|
|
656
|
-
util.info("Multiple SOF files found:")
|
|
657
|
-
for sf in sof_files:
|
|
658
|
-
util.info(f" {sf}")
|
|
659
|
-
return
|
|
660
|
-
self.error("Multiple SOF files found, please specify --sof-file")
|
|
661
|
-
elif not sof_files:
|
|
662
|
-
if self.args['list-sof-files']:
|
|
663
|
-
util.info("No SOF files found")
|
|
664
|
-
return
|
|
665
|
-
self.error("No SOF files found")
|
|
666
|
-
|
|
667
|
-
# Generate TCL script
|
|
668
|
-
script_file = Path(self.args['tcl-file'])
|
|
669
|
-
|
|
670
|
-
try:
|
|
671
|
-
with script_file.open("w", encoding="utf-8") as fout:
|
|
672
|
-
fout.write('load_package quartus_pgm\n')
|
|
673
|
-
|
|
674
|
-
if self.args['list-cables']:
|
|
675
|
-
fout.write('foreach cable [get_hardware_names] {\n')
|
|
676
|
-
fout.write(' puts "Cable: $cable"\n')
|
|
677
|
-
fout.write('}\n')
|
|
678
|
-
|
|
679
|
-
if self.args['list-devices']:
|
|
680
|
-
cable_idx = int(self.args["cable"]) - 1
|
|
681
|
-
fout.write(f'set cable [lindex [get_hardware_names] {cable_idx}]\n')
|
|
682
|
-
fout.write('foreach device [get_device_names -hardware_name $cable] {\n')
|
|
683
|
-
fout.write(' puts "Device: $device"\n')
|
|
684
|
-
fout.write('}\n')
|
|
685
|
-
|
|
686
|
-
if sof_file:
|
|
687
|
-
cable_idx2 = int(self.args["cable"]) - 1
|
|
688
|
-
device_idx = int(self.args["device"]) - 1
|
|
689
|
-
fout.write(f'set cable [lindex [get_hardware_names] {cable_idx2}]\n')
|
|
690
|
-
device_cmd = (
|
|
691
|
-
f'set device [lindex [get_device_names -hardware_name $cable] {device_idx}]'
|
|
692
|
-
)
|
|
693
|
-
fout.write(device_cmd)
|
|
694
|
-
fout.write('set_global_assignment -name USE_CONFIGURATION_DEVICE OFF\n')
|
|
695
|
-
fout.write('execute_flow -compile\n')
|
|
696
|
-
fout.write(f'quartus_pgm -c $cable -m jtag -o "p;{sof_file}@$device"\n')
|
|
697
|
-
|
|
698
|
-
except Exception as exc:
|
|
699
|
-
self.error(f"Cannot create {script_file}: {exc}")
|
|
700
|
-
|
|
701
|
-
if sof_file:
|
|
702
|
-
util.info(f"Programming with SOF file: {sof_file}")
|
|
703
|
-
else:
|
|
704
|
-
util.info("Listing cables/devices only")
|
|
677
|
+
if not sof_file:
|
|
678
|
+
# CommandUpload already displayed them, and exited on --list-bitfiles.
|
|
679
|
+
if len(self.bitfiles) > 1:
|
|
680
|
+
self.error("Multiple SOF files found, please specify --sof-file or --bitfile",
|
|
681
|
+
"or use a different search pattern")
|
|
682
|
+
return
|
|
683
|
+
|
|
684
|
+
self.error("No SOF files found")
|
|
685
|
+
return
|
|
686
|
+
|
|
687
|
+
util.info(f"Programming with SOF file: {sof_file}")
|
|
688
|
+
|
|
705
689
|
|
|
706
690
|
# Execute Quartus programmer
|
|
691
|
+
# Format: quartus_pgm -c <cable> -m jtag -o "p;<sof_file>@<device>"
|
|
692
|
+
cable = self.args['cable']
|
|
693
|
+
device = self.args['device']
|
|
694
|
+
operation = f"p;{sof_file}@{device}"
|
|
695
|
+
|
|
707
696
|
command_list = [
|
|
708
|
-
|
|
697
|
+
quartus_pgm, '-c', cable, '-m', 'jtag', '-o', operation
|
|
709
698
|
]
|
|
710
|
-
if not util.args['verbose']:
|
|
711
|
-
command_list.append('-q')
|
|
712
699
|
|
|
713
|
-
self.exec(self.args['work-dir'], command_list)
|
|
700
|
+
_, stdout, _ = self.exec(self.args['work-dir'], command_list)
|
|
701
|
+
|
|
702
|
+
# Do some log scraping
|
|
703
|
+
for line in stdout.split('\n'):
|
|
704
|
+
if any(x in line for x in ('Warning', 'WARNING')):
|
|
705
|
+
self.tool_warning_count += 1
|
|
706
|
+
elif any(x in line for x in ('Error', 'ERROR')):
|
|
707
|
+
self.tool_error_count += 1
|
|
708
|
+
|
|
709
|
+
self.report_tool_warn_error_counts()
|
|
710
|
+
self.report_pass_fail()
|
|
711
|
+
|
|
714
712
|
util.info("Upload operation completed")
|
|
715
713
|
|
|
716
714
|
|
opencos/tools/questa_common.py
CHANGED
|
@@ -11,11 +11,11 @@ Contains classes for ToolQuesta, and CommonSimQuesta.
|
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
13
|
import re
|
|
14
|
-
import shutil
|
|
15
14
|
|
|
16
15
|
from opencos import util
|
|
17
16
|
from opencos.commands import sim, CommandSim, CommandFList
|
|
18
17
|
from opencos.eda_base import Tool
|
|
18
|
+
from opencos.files import safe_shutil_which
|
|
19
19
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
20
20
|
|
|
21
21
|
class ToolQuesta(Tool):
|
|
@@ -37,7 +37,7 @@ class ToolQuesta(Tool):
|
|
|
37
37
|
def get_versions(self) -> str:
|
|
38
38
|
if self._VERSION:
|
|
39
39
|
return self._VERSION
|
|
40
|
-
path =
|
|
40
|
+
path = safe_shutil_which(self._EXE)
|
|
41
41
|
if not path:
|
|
42
42
|
self.error(f"{self._EXE} not in path, need to setup",
|
|
43
43
|
"(i.e. source /opt/intelFPGA_pro/23.4/settings64.sh")
|
opencos/tools/riviera.py
CHANGED
|
@@ -7,12 +7,12 @@ Contains classes for ToolRiviera, CommandSimRiviera, CommandElabRiviera.
|
|
|
7
7
|
# pylint: disable=R0801 # (duplicate code in derived classes, such as if-condition return.)
|
|
8
8
|
|
|
9
9
|
import os
|
|
10
|
-
import shutil
|
|
11
10
|
import subprocess
|
|
12
11
|
|
|
13
12
|
from opencos import util
|
|
14
|
-
from opencos.tools.questa_common import ToolQuesta, CommonSimQuesta
|
|
15
13
|
from opencos.commands import CommandFList
|
|
14
|
+
from opencos.files import safe_shutil_which
|
|
15
|
+
from opencos.tools.questa_common import ToolQuesta, CommonSimQuesta
|
|
16
16
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
17
17
|
from opencos.utils import status_constants
|
|
18
18
|
|
|
@@ -27,7 +27,7 @@ class ToolRiviera(ToolQuesta):
|
|
|
27
27
|
def get_versions(self) -> str:
|
|
28
28
|
if self._VERSION:
|
|
29
29
|
return self._VERSION
|
|
30
|
-
path =
|
|
30
|
+
path = safe_shutil_which(self._EXE)
|
|
31
31
|
if not path:
|
|
32
32
|
self.error(f"{self._EXE} not in path, need to setup or add to PATH")
|
|
33
33
|
util.debug(f"{path=}")
|
opencos/tools/slang.py
CHANGED
|
@@ -6,12 +6,12 @@ Contains classes for ToolSlang, CommandElabSlang
|
|
|
6
6
|
# pylint: disable=R0801 # (calling functions with same arguments)
|
|
7
7
|
|
|
8
8
|
import os
|
|
9
|
-
import shutil
|
|
10
9
|
import subprocess
|
|
11
10
|
|
|
12
11
|
from opencos import util
|
|
13
|
-
from opencos.eda_base import Tool
|
|
14
12
|
from opencos.commands import CommandElab
|
|
13
|
+
from opencos.eda_base import Tool
|
|
14
|
+
from opencos.files import safe_shutil_which
|
|
15
15
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
16
16
|
|
|
17
17
|
|
|
@@ -30,14 +30,18 @@ class ToolSlang(Tool):
|
|
|
30
30
|
def get_versions(self) -> str:
|
|
31
31
|
if self._VERSION:
|
|
32
32
|
return self._VERSION
|
|
33
|
-
path =
|
|
33
|
+
path = safe_shutil_which(self._EXE)
|
|
34
34
|
if not path:
|
|
35
35
|
self.error(f'"{self._EXE}" not in path, need to get it ({self._URL}')
|
|
36
36
|
else:
|
|
37
37
|
self.slang_exe = path
|
|
38
38
|
self.slang_base_path, _ = os.path.split(path)
|
|
39
|
-
self.slang_tidy_exe =
|
|
40
|
-
|
|
39
|
+
self.slang_tidy_exe = safe_shutil_which(
|
|
40
|
+
os.path.join(self.slang_base_path, 'slang-tidy')
|
|
41
|
+
)
|
|
42
|
+
self.slang_hier_exe = safe_shutil_which(
|
|
43
|
+
os.path.join(self.slang_base_path, 'slang-hier')
|
|
44
|
+
)
|
|
41
45
|
|
|
42
46
|
version_ret = subprocess.run(
|
|
43
47
|
[self.slang_exe, '--version'],
|
|
@@ -204,7 +208,7 @@ class CommandElabSlang(CommandElab, ToolSlang):
|
|
|
204
208
|
command_list = [self.slang_exe]
|
|
205
209
|
|
|
206
210
|
if self.args['tidy']:
|
|
207
|
-
if not
|
|
211
|
+
if not safe_shutil_which(self.slang_tidy_exe):
|
|
208
212
|
util.warning("Running tool slang with --tidy, but 'slang-tidy'",
|
|
209
213
|
"not in PATH, using 'slang' instead")
|
|
210
214
|
else:
|
|
@@ -213,7 +217,7 @@ class CommandElabSlang(CommandElab, ToolSlang):
|
|
|
213
217
|
if self.args['hier']:
|
|
214
218
|
if self.args['tidy']:
|
|
215
219
|
util.warning('Running with --tidy and --heir, will attempt to use slang-hier')
|
|
216
|
-
elif not
|
|
220
|
+
elif not safe_shutil_which(self.slang_hier_exe):
|
|
217
221
|
util.warning("Running tool slang with --hier, but 'slang-hier'",
|
|
218
222
|
"not in PATH, using 'slang' instead")
|
|
219
223
|
else:
|
opencos/tools/slang_yosys.py
CHANGED
|
@@ -119,6 +119,7 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
119
119
|
)
|
|
120
120
|
|
|
121
121
|
# In case --top was not set:
|
|
122
|
+
# TODO(drew): Can we skip this if it was an inferred top???
|
|
122
123
|
if not any(x.startswith('--top') for x in read_slang_cmd):
|
|
123
124
|
read_slang_cmd.append(f'--top {self.args["top"]}')
|
|
124
125
|
|
opencos/tools/surelog.py
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
Contains classes for ToolSurelog, CommandElabSurelog
|
|
4
4
|
'''
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
import subprocess
|
|
8
8
|
|
|
9
9
|
from opencos import util
|
|
10
|
-
from opencos.eda_base import Tool
|
|
11
10
|
from opencos.commands import CommandElab
|
|
11
|
+
from opencos.eda_base import Tool
|
|
12
|
+
from opencos.files import safe_shutil_which
|
|
12
13
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
13
14
|
|
|
14
15
|
|
|
@@ -24,7 +25,7 @@ class ToolSurelog(Tool):
|
|
|
24
25
|
def get_versions(self) -> str:
|
|
25
26
|
if self._VERSION:
|
|
26
27
|
return self._VERSION
|
|
27
|
-
path =
|
|
28
|
+
path = safe_shutil_which(self._EXE)
|
|
28
29
|
if not path:
|
|
29
30
|
self.error(f'"{self._EXE}" not in path, need to get it ({self._URL})')
|
|
30
31
|
else:
|
opencos/tools/verilator.py
CHANGED
|
@@ -7,13 +7,13 @@ Contains classes for ToolVerilator and VerilatorSim, VerilatorElab.
|
|
|
7
7
|
|
|
8
8
|
import multiprocessing
|
|
9
9
|
import os
|
|
10
|
-
import shutil
|
|
11
10
|
import subprocess
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
from opencos import util
|
|
15
|
-
from opencos.eda_base import Tool
|
|
16
14
|
from opencos.commands import CommandSim
|
|
15
|
+
from opencos.eda_base import Tool
|
|
16
|
+
from opencos.files import safe_shutil_which
|
|
17
17
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
18
18
|
|
|
19
19
|
class ToolVerilator(Tool):
|
|
@@ -31,7 +31,7 @@ class ToolVerilator(Tool):
|
|
|
31
31
|
if self._VERSION:
|
|
32
32
|
return self._VERSION
|
|
33
33
|
# __init__ would have set self.EXE to full path.
|
|
34
|
-
path =
|
|
34
|
+
path = safe_shutil_which(self._EXE)
|
|
35
35
|
if not path:
|
|
36
36
|
self.error(f'"{self._EXE}" not in path or not installed, see {self._URL})')
|
|
37
37
|
else:
|
|
@@ -40,7 +40,7 @@ class ToolVerilator(Tool):
|
|
|
40
40
|
|
|
41
41
|
# Let's get the verilator_coverage path from the same place as verilator.
|
|
42
42
|
if path:
|
|
43
|
-
self.verilator_coverage_exe =
|
|
43
|
+
self.verilator_coverage_exe = safe_shutil_which(
|
|
44
44
|
os.path.join(self.verilator_base_path, 'verilator_coverage')
|
|
45
45
|
)
|
|
46
46
|
if not self.verilator_coverage_exe:
|