opencos-eda 0.3.15__py3-none-any.whl → 0.3.17__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/flist.py +143 -88
- opencos/commands/shell.py +1 -1
- opencos/commands/sim.py +21 -8
- opencos/commands/waves.py +3 -1
- opencos/deps/defaults.py +6 -2
- opencos/deps/deps_file.py +30 -9
- opencos/deps/deps_processor.py +99 -65
- opencos/deps_schema.py +8 -0
- opencos/docs/DEPS.md +6 -0
- opencos/eda.py +30 -5
- opencos/eda_base.py +21 -9
- opencos/eda_config.py +2 -1
- opencos/eda_config_defaults.yml +9 -1
- opencos/eda_tool_helper.py +84 -9
- opencos/files.py +41 -0
- opencos/tools/cocotb.py +1 -1
- opencos/tools/invio.py +1 -1
- opencos/tools/invio_yosys.py +1 -1
- opencos/tools/iverilog.py +1 -1
- opencos/tools/quartus.py +1 -1
- opencos/tools/questa_common.py +6 -3
- opencos/tools/riviera.py +5 -3
- opencos/tools/slang.py +1 -1
- opencos/tools/slang_yosys.py +36 -8
- opencos/tools/surelog.py +1 -1
- opencos/tools/verilator.py +209 -20
- opencos/tools/vivado.py +1 -1
- opencos/tools/yosys.py +155 -30
- opencos/util.py +5 -1
- opencos/utils/docker_checks.py +224 -0
- opencos/utils/subprocess_helpers.py +3 -1
- {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/METADATA +1 -1
- {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/RECORD +38 -37
- {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/WHEEL +0 -0
- {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.3.15.dist-info → opencos_eda-0.3.17.dist-info}/top_level.txt +0 -0
opencos/deps/deps_processor.py
CHANGED
|
@@ -4,8 +4,11 @@ a DEPS markup files targets (applying deps, reqs, commands, tags, incdirs, defin
|
|
|
4
4
|
CommandDesign ref object
|
|
5
5
|
'''
|
|
6
6
|
|
|
7
|
+
# pylint: disable=too-many-lines
|
|
8
|
+
|
|
7
9
|
import argparse
|
|
8
10
|
import copy
|
|
11
|
+
import glob
|
|
9
12
|
import os
|
|
10
13
|
|
|
11
14
|
from opencos import files
|
|
@@ -418,7 +421,8 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
418
421
|
self.process_commands()
|
|
419
422
|
elif key == 'reqs':
|
|
420
423
|
self.process_reqs()
|
|
421
|
-
elif key == 'deps'
|
|
424
|
+
elif key == 'deps' or \
|
|
425
|
+
(key == 'files' and 'deps' not in self.deps_entry):
|
|
422
426
|
remaining_deps_list += self.process_deps_return_discovered_deps()
|
|
423
427
|
|
|
424
428
|
if self.command_design_ref.tool_changed_respawn:
|
|
@@ -528,10 +532,10 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
528
532
|
with_args_matched_list = []
|
|
529
533
|
for k,v in with_args.items():
|
|
530
534
|
with_args_matched_list.append(False)
|
|
531
|
-
if not apply_tag_items_tools:
|
|
535
|
+
if not all((apply_tag_items_tools, apply_tag_items_commands)):
|
|
532
536
|
# If we didn't previously match with-tools (if with-tools was present),
|
|
533
|
-
# then we may not match the args, b/c those are
|
|
534
|
-
# Command handling class.
|
|
537
|
+
# or match with-commands, then we may not match the args, b/c those are
|
|
538
|
+
# command + tool dependent in the Command handling class.
|
|
535
539
|
pass
|
|
536
540
|
elif k not in self.command_design_ref.args:
|
|
537
541
|
warning(f'{tagname=} in {self.caller_info}:',
|
|
@@ -613,7 +617,8 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
613
617
|
deps_file=self.deps_file)
|
|
614
618
|
self.apply_reqs(reqs_list)
|
|
615
619
|
|
|
616
|
-
elif key == 'deps'
|
|
620
|
+
elif key == 'deps' or \
|
|
621
|
+
(key == 'files' and 'deps' not in tags_dict_to_apply):
|
|
617
622
|
|
|
618
623
|
# apply deps (includes commands, stray +define+ +incdir+)
|
|
619
624
|
# treat the same way we treat self.process_deps_return_discovered_deps
|
|
@@ -861,6 +866,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
861
866
|
'''Returns list of deps targets to continue processing,
|
|
862
867
|
|
|
863
868
|
-- iterates through 'deps' for this target (self.deps_entry['deps'])
|
|
869
|
+
-- note this will also append 'files' if that table key + list/str exists.
|
|
864
870
|
-- applies to self.command_design_ref
|
|
865
871
|
'''
|
|
866
872
|
|
|
@@ -872,7 +878,9 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
872
878
|
)
|
|
873
879
|
return self.get_remaining_and_apply_deps(deps)
|
|
874
880
|
|
|
875
|
-
def get_remaining_and_apply_deps(
|
|
881
|
+
def get_remaining_and_apply_deps(
|
|
882
|
+
self, deps: list
|
|
883
|
+
) -> list:
|
|
876
884
|
'''Given a list of deps, process what is supported in a "deps:" table in DEPS
|
|
877
885
|
markup file.'''
|
|
878
886
|
|
|
@@ -880,66 +888,98 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
880
888
|
|
|
881
889
|
# Process deps (list)
|
|
882
890
|
for dep in deps:
|
|
891
|
+
deps_targets_to_resolve.extend(
|
|
892
|
+
self._get_remaining_and_apply_single_dep(dep)
|
|
893
|
+
)
|
|
894
|
+
return deps_targets_to_resolve
|
|
895
|
+
|
|
883
896
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
for supported_values in SUPPORTED_DEP_KEYS_BY_TYPE.values():
|
|
890
|
-
if '*' in supported_values:
|
|
891
|
-
continue
|
|
892
|
-
if typ in [dict,list] and any(k not in supported_values for k in dep):
|
|
893
|
-
self.error(
|
|
894
|
-
f'{self.target_node=} {dep=} in {self.deps_file=}: has dict-key or',
|
|
895
|
-
f'list-item not in {SUPPORTED_DEP_KEYS_BY_TYPE[typ]=}'
|
|
896
|
-
)
|
|
897
|
-
|
|
898
|
-
# In-line commands in the deps list, in case the results need to be in strict file
|
|
899
|
-
# order for other deps
|
|
900
|
-
if isinstance(dep, dict) and 'commands' in dep:
|
|
901
|
-
|
|
902
|
-
commands = dep['commands']
|
|
903
|
-
debug(f"Got commands {dep=} for in {self.caller_info}, {commands=}")
|
|
904
|
-
|
|
905
|
-
assert isinstance(commands, list), \
|
|
906
|
-
f'dep commands must be a list: {dep=} in {self.caller_info}'
|
|
907
|
-
|
|
908
|
-
# For this, we need to get the returned commands (to keep strict order w/ other
|
|
909
|
-
# deps)
|
|
910
|
-
command_tuple = self.get_commands( commands=commands, dep=dep )
|
|
911
|
-
# TODO(drew): it might be cleaner to return a dict instead of list, b/c those
|
|
912
|
-
# are also ordered and we can pass type information, something like:
|
|
913
|
-
deps_targets_to_resolve.append(command_tuple)
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
elif isinstance(dep, str) and \
|
|
917
|
-
any(dep.startswith(x) for x in ['+define+', '+incdir+']) and \
|
|
918
|
-
self.is_command_design:
|
|
919
|
-
# Note: we still support +define+ and +incdir in the deps list.
|
|
920
|
-
# check for compile-time Verilog style plusarg, which are supported under targets
|
|
921
|
-
# These are not run-time Verilog style plusargs comsumable from within the .sv:
|
|
922
|
-
debug(f"Got plusarg (define, incdir) {dep=} for {self.caller_info}")
|
|
923
|
-
self.command_design_ref.process_plusarg(plusarg=dep, pwd=self.target_path)
|
|
897
|
+
def _get_remaining_and_apply_single_dep( # pylint: disable=too-many-branches
|
|
898
|
+
self, dep: str
|
|
899
|
+
) -> list:
|
|
900
|
+
'''Given a single dep, process is and return targets/files that need resolving'''
|
|
924
901
|
|
|
902
|
+
deps_targets_to_resolve = []
|
|
903
|
+
typ = type(dep)
|
|
904
|
+
if typ not in SUPPORTED_DEP_KEYS_BY_TYPE:
|
|
905
|
+
self.error(f'{self.target_node=} {dep=} in {self.deps_file=}:' \
|
|
906
|
+
+ f'has unsupported {type(dep)=} {SUPPORTED_DEP_KEYS_BY_TYPE=}')
|
|
907
|
+
|
|
908
|
+
for supported_values in SUPPORTED_DEP_KEYS_BY_TYPE.values():
|
|
909
|
+
if '*' in supported_values:
|
|
910
|
+
continue
|
|
911
|
+
if typ in [dict,list] and any(k not in supported_values for k in dep):
|
|
912
|
+
self.error(
|
|
913
|
+
f'{self.target_node=} {dep=} in {self.deps_file=}: has dict-key or',
|
|
914
|
+
f'list-item not in {SUPPORTED_DEP_KEYS_BY_TYPE[typ]=}'
|
|
915
|
+
)
|
|
916
|
+
|
|
917
|
+
# In-line commands in the deps list, in case the results need to be in strict file
|
|
918
|
+
# order for other deps
|
|
919
|
+
if isinstance(dep, dict) and 'commands' in dep:
|
|
920
|
+
|
|
921
|
+
commands = dep['commands']
|
|
922
|
+
debug(f"Got commands {dep=} for in {self.caller_info}, {commands=}")
|
|
923
|
+
|
|
924
|
+
assert isinstance(commands, list), \
|
|
925
|
+
f'dep commands must be a list: {dep=} in {self.caller_info}'
|
|
926
|
+
|
|
927
|
+
# For this, we need to get the returned commands (to keep strict order w/ other
|
|
928
|
+
# deps)
|
|
929
|
+
command_tuple = self.get_commands( commands=commands, dep=dep )
|
|
930
|
+
# TODO(drew): it might be cleaner to return a dict instead of list, b/c those
|
|
931
|
+
# are also ordered and we can pass type information, something like:
|
|
932
|
+
deps_targets_to_resolve.append(command_tuple)
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
elif isinstance(dep, str) and \
|
|
936
|
+
any(dep.startswith(x) for x in ['+define+', '+incdir+']) and \
|
|
937
|
+
self.is_command_design:
|
|
938
|
+
# Note: we still support +define+ and +incdir in the deps list.
|
|
939
|
+
# check for compile-time Verilog style plusarg, which are supported under targets
|
|
940
|
+
# These are not run-time Verilog style plusargs comsumable from within the .sv:
|
|
941
|
+
debug(f"Got plusarg (define, incdir) {dep=} for {self.caller_info}")
|
|
942
|
+
self.command_design_ref.process_plusarg(plusarg=dep, pwd=self.target_path)
|
|
943
|
+
|
|
944
|
+
else:
|
|
945
|
+
# If we made it this far, dep better be a str type.
|
|
946
|
+
assert isinstance(dep, str), f'{dep=} {type(dep)=} must be str'
|
|
947
|
+
dep_path = self.correct_a_deps_target(target=dep, deps_dir=self.target_path)
|
|
948
|
+
debug(f"Got dep {dep_path=} for in {self.caller_info}")
|
|
949
|
+
|
|
950
|
+
if self.is_command_design and \
|
|
951
|
+
dep_path in self.command_design_ref.targets_dict or \
|
|
952
|
+
dep_path in deps_targets_to_resolve:
|
|
953
|
+
debug(f" - already processed ({dep_path}), skipping")
|
|
925
954
|
else:
|
|
926
|
-
#
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
955
|
+
# This is where we support files/deps file wildcards via glob syntax.
|
|
956
|
+
# If glob found none, we fall back to a single-file or target
|
|
957
|
+
glob_added_from_dep_path = False
|
|
958
|
+
if any(x in dep_path for x in ('*', '?', '[')):
|
|
959
|
+
try:
|
|
960
|
+
glob_list = glob.glob(dep_path)
|
|
961
|
+
for fpath in glob_list:
|
|
962
|
+
file_exists, _, _ = files.get_source_file(fpath)
|
|
963
|
+
if file_exists:
|
|
964
|
+
debug(f" - raw file ({fpath}), from glob ({dep_path}) adding",
|
|
965
|
+
"to return list...")
|
|
966
|
+
deps_targets_to_resolve.append(fpath) # append
|
|
967
|
+
glob_added_from_dep_path = True
|
|
968
|
+
if glob_list and not glob_added_from_dep_path:
|
|
969
|
+
self.error(f'No files were expanded from glob: {dep_path} in',
|
|
970
|
+
f'{self.caller_info}')
|
|
971
|
+
except Exception as e:
|
|
972
|
+
self.error(f'Unable to add files via glob {dep_path}, in',
|
|
973
|
+
f'{self.caller_info}exception {e}')
|
|
974
|
+
|
|
975
|
+
if not glob_added_from_dep_path:
|
|
936
976
|
file_exists, _, _ = files.get_source_file(dep_path)
|
|
937
977
|
if file_exists:
|
|
938
|
-
debug(" - raw file, adding to return list...")
|
|
978
|
+
debug(f" - raw file ({dep_path}), adding to return list...")
|
|
939
979
|
deps_targets_to_resolve.append(dep_path) # append, keeping file order.
|
|
940
980
|
else:
|
|
941
|
-
debug(" - a target (
|
|
942
|
-
"list...")
|
|
981
|
+
debug(f" - a target non-file ({dep_path}) needs to be resolved,",
|
|
982
|
+
"adding to return list...")
|
|
943
983
|
deps_targets_to_resolve.append(dep_path) # append, keeping file order.
|
|
944
984
|
|
|
945
985
|
# We return the list of deps or files that still need to be resolved
|
|
@@ -947,12 +987,6 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
947
987
|
# items in this list are either:
|
|
948
988
|
# -- string (dep or file)
|
|
949
989
|
# -- tuple (unprocessed commands, in form: (shell_commands_list, work_dir_add_srcs_list))
|
|
950
|
-
# TODO(drew): it might be cleaner to return a dict instead of list, b/c those are also
|
|
951
|
-
# ordered and we can pass type information, something like:
|
|
952
|
-
# { dep1: 'file',
|
|
953
|
-
# dep2: 'target',
|
|
954
|
-
# dep3: 'command_tuple',
|
|
955
|
-
# }
|
|
956
990
|
return deps_targets_to_resolve
|
|
957
991
|
|
|
958
992
|
|
opencos/deps_schema.py
CHANGED
|
@@ -264,6 +264,9 @@ TARGET_TAGS_TABLE = {
|
|
|
264
264
|
TARGET_CONTENTS = Or(
|
|
265
265
|
ARRAY_OR_SPACE_SEPARATED_STRING,
|
|
266
266
|
{
|
|
267
|
+
# description, info: str
|
|
268
|
+
Optional('description'): Or(str, type(None)),
|
|
269
|
+
Optional('info'): Or(str, type(None)),
|
|
267
270
|
# args: array
|
|
268
271
|
Optional('args'): ARRAY_OR_SPACE_SEPARATED_STRING,
|
|
269
272
|
# commands: array
|
|
@@ -285,7 +288,9 @@ TARGET_CONTENTS = Or(
|
|
|
285
288
|
# top: string
|
|
286
289
|
Optional('top'): str,
|
|
287
290
|
# deps: array
|
|
291
|
+
# AND/OR files: array
|
|
288
292
|
Optional('deps'): TARGET_DEPS_CONTENTS,
|
|
293
|
+
Optional('files'): TARGET_DEPS_CONTENTS,
|
|
289
294
|
# reqs: array
|
|
290
295
|
Optional('reqs'): ARRAY_OR_SPACE_SEPARATED_STRING,
|
|
291
296
|
# multi: table
|
|
@@ -334,6 +339,8 @@ FILE_SIMPLIFIED = Schema(
|
|
|
334
339
|
Optional('METADATA'): dict,
|
|
335
340
|
Optional(str): Or( # User named target contents
|
|
336
341
|
{
|
|
342
|
+
Optional('description'): str,
|
|
343
|
+
Optional('info'): str,
|
|
337
344
|
Optional('args'): [str],
|
|
338
345
|
Optional('defines'): {
|
|
339
346
|
Optional(str): Or(type(None), int, str),
|
|
@@ -347,6 +354,7 @@ FILE_SIMPLIFIED = Schema(
|
|
|
347
354
|
Optional('incdirs'): [str],
|
|
348
355
|
Optional('top'): str,
|
|
349
356
|
Optional('deps'): [str],
|
|
357
|
+
Optional('files'): [str],
|
|
350
358
|
Optional('reqs'): [str],
|
|
351
359
|
}
|
|
352
360
|
)
|
opencos/docs/DEPS.md
CHANGED
|
@@ -9,6 +9,9 @@ METADATA: # <table> unstructured data, any UPPERCASE first level key is not cons
|
|
|
9
9
|
|
|
10
10
|
target-spec:
|
|
11
11
|
|
|
12
|
+
description: # <str> optional description
|
|
13
|
+
info: # <str> optional description
|
|
14
|
+
|
|
12
15
|
args: # <array or | separated str>
|
|
13
16
|
- --waves
|
|
14
17
|
- --sim_plusargs="+info=500"
|
|
@@ -56,6 +59,8 @@ target-spec:
|
|
|
56
59
|
# to compile order list.
|
|
57
60
|
- peakrdl: # <string> ## peakrdl command to generate CSRs
|
|
58
61
|
|
|
62
|
+
files: # <Identical to "deps", will append to any deps.>
|
|
63
|
+
|
|
59
64
|
reqs: # <array or | space separated string>
|
|
60
65
|
- some_file.mem # <string> aka, a non-source file required for this target.
|
|
61
66
|
# This file is checked for existence prior to invoking the tool involved, for example,
|
|
@@ -100,6 +105,7 @@ target-spec:
|
|
|
100
105
|
args: <array or | space separated string> # args to be applied if this target is used, with a matching
|
|
101
106
|
# tool in 'with-tools'.
|
|
102
107
|
deps: <array or | space separated string, applied with tag>
|
|
108
|
+
files: <identical to deps, will append to deps>
|
|
103
109
|
defines: <table, applied with tag>
|
|
104
110
|
plusargs: <table, applied with tag>
|
|
105
111
|
parameters: <table, applied with tag>
|
opencos/eda.py
CHANGED
|
@@ -20,10 +20,11 @@ from pathlib import Path
|
|
|
20
20
|
import opencos
|
|
21
21
|
from opencos import util, eda_config, eda_base
|
|
22
22
|
from opencos.eda_base import Command, Tool, which_tool, print_eda_usage_line
|
|
23
|
-
from opencos.eda_tool_helper import pretty_info_handler_tools
|
|
23
|
+
from opencos.eda_tool_helper import DOCKER_TOOL_NOTE, pretty_info_handler_tools, \
|
|
24
|
+
tool_loaded_but_flagged_as_docker_only, get_all_handler_commands
|
|
24
25
|
from opencos.files import safe_shutil_which
|
|
25
26
|
from opencos.util import safe_emoji, Colors
|
|
26
|
-
from opencos.utils import vsim_helper, vscode_helper
|
|
27
|
+
from opencos.utils import vsim_helper, vscode_helper, docker_checks
|
|
27
28
|
from opencos.utils import status_constants, str_helpers, subprocess_helpers
|
|
28
29
|
|
|
29
30
|
# Configure util:
|
|
@@ -99,9 +100,17 @@ def init_config(
|
|
|
99
100
|
def get_all_commands_help_str(config: dict) -> str:
|
|
100
101
|
'''Returns a str of help based on what commands eda supports, from config'''
|
|
101
102
|
all_commands_help = []
|
|
103
|
+
all_handler_commands = get_all_handler_commands(config=config)
|
|
102
104
|
max_command_str_len = max(len(s) for s in config.get('DEFAULT_HANDLERS_HELP', {}).keys())
|
|
103
105
|
for key, value in config.get('DEFAULT_HANDLERS_HELP', {}).items():
|
|
104
|
-
all_commands_help.append(
|
|
106
|
+
all_commands_help.append(
|
|
107
|
+
f' {Colors.bcyan}{key:<{max_command_str_len}}{Colors.normal} - {value.strip()}'
|
|
108
|
+
)
|
|
109
|
+
if key in all_handler_commands:
|
|
110
|
+
all_commands_help[-1] += (
|
|
111
|
+
f'\n {" ":<{max_command_str_len}} '
|
|
112
|
+
f'--tool: {Colors.cyan}{", ".join(all_handler_commands[key])}{Colors.normal}'
|
|
113
|
+
)
|
|
105
114
|
if all_commands_help:
|
|
106
115
|
all_commands_help = [
|
|
107
116
|
f'Where {Colors.byellow}COMMAND{Colors.normal} is one of:',
|
|
@@ -277,13 +286,21 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
277
286
|
if not exe_path:
|
|
278
287
|
exe_path = p # set on first required exe
|
|
279
288
|
if not p:
|
|
280
|
-
has_all_exe
|
|
289
|
+
# skip the fail (has_all_exe=False) if we can run via docker.
|
|
290
|
+
if tool_cfg.get('docker_support', None):
|
|
291
|
+
if not docker_checks.docker_ok():
|
|
292
|
+
has_all_exe = False
|
|
293
|
+
util.debug("... No, missing docker requirements")
|
|
294
|
+
else:
|
|
295
|
+
has_all_exe = False
|
|
281
296
|
util.debug(f"... No, missing exe {exe}")
|
|
282
297
|
for req in tool_cfg.get('requires_in_exe_path', []):
|
|
283
298
|
if p and req and str(Path(req)) not in str(Path(p)):
|
|
284
299
|
has_all_in_exe_path = False
|
|
285
300
|
util.debug(f"... No, missing path requirement {req}")
|
|
286
301
|
|
|
302
|
+
|
|
303
|
+
|
|
287
304
|
has_vsim_helper = True
|
|
288
305
|
if tool_cfg.get('requires_vsim_helper', False):
|
|
289
306
|
# This tool name must be in opencos.utils.vsim_helper.TOOL_PATH[name].
|
|
@@ -327,6 +344,9 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
327
344
|
p = exe_path
|
|
328
345
|
else:
|
|
329
346
|
p = safe_shutil_which(exe_list[0])
|
|
347
|
+
if not p and tool_cfg.get('docker_support', None) and docker_checks.docker_ok():
|
|
348
|
+
# Sets note that this tool is loaded, but only avail via docker:
|
|
349
|
+
p = DOCKER_TOOL_NOTE
|
|
330
350
|
config['auto_tools_found'][name] = p # populate key-value pairs w/ first exe in list
|
|
331
351
|
if name not in config['tools_loaded']:
|
|
332
352
|
config['tools_loaded'].append(name)
|
|
@@ -357,7 +377,7 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
357
377
|
)
|
|
358
378
|
return config
|
|
359
379
|
|
|
360
|
-
# If --tool was not set, look at config['
|
|
380
|
+
# If --tool was not set, look at config['auto_tools_order'] should be populated based on
|
|
361
381
|
# config['tools'], and if we called this method (auto_tool_setup(...)) with tool= and command=
|
|
362
382
|
# arg(s). Call set_command_handlers for each command/tool we need to:
|
|
363
383
|
for _command, list_of_tools in config['auto_tools_order'].items():
|
|
@@ -365,6 +385,10 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
365
385
|
for _tool in list_of_tools:
|
|
366
386
|
if _tool not in config['tools_loaded']:
|
|
367
387
|
continue
|
|
388
|
+
if tool_loaded_but_flagged_as_docker_only(tool=_tool, config=config):
|
|
389
|
+
# do not let this tool be the auto-handler for a command (aka, it is the
|
|
390
|
+
# chosen tool if --tool=TOOL arg not present) if it can only run via docker.
|
|
391
|
+
continue
|
|
368
392
|
|
|
369
393
|
set_command_handler(
|
|
370
394
|
command=_command, tool=_tool, config=config, auto_setup=(not tool),
|
|
@@ -801,6 +825,7 @@ def main(*args):
|
|
|
801
825
|
# And show python version:
|
|
802
826
|
util.info(f'python: version {sys.version_info.major}.{sys.version_info.minor}.'
|
|
803
827
|
f'{sys.version_info.micro}')
|
|
828
|
+
util.info(f'eda from: {__file__}')
|
|
804
829
|
|
|
805
830
|
# Handle --config-yml= arg
|
|
806
831
|
config, unparsed = eda_config.get_eda_config(unparsed)
|
opencos/eda_base.py
CHANGED
|
@@ -203,7 +203,7 @@ class Tool:
|
|
|
203
203
|
})
|
|
204
204
|
# update self._EXE if config says to:
|
|
205
205
|
self.set_exe(config)
|
|
206
|
-
self.get_versions()
|
|
206
|
+
self.get_versions(quiet=True)
|
|
207
207
|
|
|
208
208
|
if getattr(self, 'set_tool_config_from_config', None):
|
|
209
209
|
# Hook for classes like CommandSim that have a Tool derived class attached:
|
|
@@ -233,7 +233,9 @@ class Tool:
|
|
|
233
233
|
self.get_versions()
|
|
234
234
|
return str(self._TOOL) + ':' + str(self._VERSION)
|
|
235
235
|
|
|
236
|
-
def get_versions(
|
|
236
|
+
def get_versions( # pylint: disable=unused-argument
|
|
237
|
+
self, **kwargs
|
|
238
|
+
) -> str:
|
|
237
239
|
'''Sets and returns self._VERSION. Note that this is overriden by nearly all
|
|
238
240
|
|
|
239
241
|
child Tool classes, and should limit info/warning messaging since it is part
|
|
@@ -1256,7 +1258,9 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1256
1258
|
# cached_deps: key = abspath of DEPS markup file, value is a dict with
|
|
1257
1259
|
# keys 'data' and 'line_numbers'
|
|
1258
1260
|
self.cached_deps = {}
|
|
1259
|
-
|
|
1261
|
+
|
|
1262
|
+
# targets_dict: key = str(Path(target)), value is DepsFile caller_info, or path
|
|
1263
|
+
self.targets_dict = {}
|
|
1260
1264
|
|
|
1261
1265
|
self.has_pre_compile_dep_shell_commands = False
|
|
1262
1266
|
self.has_post_tool_dep_shell_commands = False
|
|
@@ -1717,11 +1721,11 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1717
1721
|
|
|
1718
1722
|
self.target_path, self.target = os.path.split(target)
|
|
1719
1723
|
|
|
1720
|
-
if target in self.targets_dict:
|
|
1724
|
+
if str(Path(target)) in self.targets_dict:
|
|
1721
1725
|
# If we're encountered this target before, stop. We're not traversing again.
|
|
1722
1726
|
return True
|
|
1723
1727
|
|
|
1724
|
-
self.targets_dict[target] =
|
|
1728
|
+
self.targets_dict[str(Path(target))] = f'({self.target_path})'
|
|
1725
1729
|
file_exists, fpath, forced_extension = files.get_source_file(target)
|
|
1726
1730
|
if file_exists:
|
|
1727
1731
|
# If the target is a file (we're at the root here processing CLI arg tokens)
|
|
@@ -1748,6 +1752,7 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1748
1752
|
|
|
1749
1753
|
deps, data, deps_file = None, None, None
|
|
1750
1754
|
found_deps_file = False
|
|
1755
|
+
found_caller_info = ''
|
|
1751
1756
|
|
|
1752
1757
|
if self.config['deps_markup_supported']:
|
|
1753
1758
|
deps = DepsFile(
|
|
@@ -1763,6 +1768,7 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1763
1768
|
|
|
1764
1769
|
if found_deps_file and found_target:
|
|
1765
1770
|
|
|
1771
|
+
found_caller_info = deps.gen_caller_info(target_node)
|
|
1766
1772
|
entry = deps.get_entry(target_node=target_node)
|
|
1767
1773
|
|
|
1768
1774
|
# For convenience, use an external class for this DEPS.yml table/dict
|
|
@@ -1799,7 +1805,7 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1799
1805
|
caller_info=caller_info )
|
|
1800
1806
|
|
|
1801
1807
|
elif x and x not in self.targets_dict:
|
|
1802
|
-
self.targets_dict[x] = None # add it before processing.
|
|
1808
|
+
self.targets_dict[str(Path(x))] = None # add it before processing.
|
|
1803
1809
|
file_exists, fpath, forced_extension = files.get_source_file(x)
|
|
1804
1810
|
if file_exists:
|
|
1805
1811
|
self.add_file(filename=fpath, caller_info=caller_info,
|
|
@@ -1810,7 +1816,6 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1810
1816
|
x, no_recursion, caller_info=caller_info
|
|
1811
1817
|
)
|
|
1812
1818
|
|
|
1813
|
-
|
|
1814
1819
|
# Done with DEPS.yml if it existed.
|
|
1815
1820
|
|
|
1816
1821
|
if not found_target:
|
|
@@ -1825,6 +1830,7 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1825
1830
|
if os.path.exists(try_file):
|
|
1826
1831
|
self.add_file(try_file, caller_info=f'n/a::{target}::n/a')
|
|
1827
1832
|
found_target = True
|
|
1833
|
+
found_caller_info = os.path.split(try_file)[0]
|
|
1828
1834
|
break # move on to the next target
|
|
1829
1835
|
if not found_target and error_on_not_found: # if STILL not found_this_target...
|
|
1830
1836
|
# allow this if --no-error-unknown-args:
|
|
@@ -1835,6 +1841,8 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1835
1841
|
)
|
|
1836
1842
|
|
|
1837
1843
|
# if we've found any target since being called, it means we found the one we were called for
|
|
1844
|
+
if found_target:
|
|
1845
|
+
self.targets_dict[str(Path(target))] = f'({found_caller_info})'
|
|
1838
1846
|
return found_target
|
|
1839
1847
|
|
|
1840
1848
|
def add_file( # pylint: disable=too-many-locals,too-many-branches,too-many-statements
|
|
@@ -2107,10 +2115,14 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
2107
2115
|
# (not from DEPS.yml) we need to override self.target if that was set. Otherwise
|
|
2108
2116
|
# it won't save to the correct work-dir:
|
|
2109
2117
|
self.target = self.args['top']
|
|
2118
|
+
self.targets_dict[str(Path(self.target_path) / self.target)] = (
|
|
2119
|
+
f'({os.path.split(top_path)[-1]})'
|
|
2120
|
+
)
|
|
2110
2121
|
self.top_details['inferred_from_last_added_source_file'] = top_path
|
|
2111
2122
|
|
|
2112
|
-
|
|
2113
|
-
util.info(f'{self.command_name}: top-most target name: {self.target}'
|
|
2123
|
+
caller_info_lookup = str(Path(self.target_path) / self.target)
|
|
2124
|
+
util.info(f'{self.command_name}: top-most target name: {self.target}',
|
|
2125
|
+
f'{self.targets_dict.get(caller_info_lookup, "")}')
|
|
2114
2126
|
|
|
2115
2127
|
if self.error_on_missing_top and not self.args.get('top', ''):
|
|
2116
2128
|
self.error("Did not get a --top or DEPS top, required to run command",
|
opencos/eda_config.py
CHANGED
|
@@ -55,7 +55,7 @@ class Defaults:
|
|
|
55
55
|
'auto_tools_order',
|
|
56
56
|
])
|
|
57
57
|
supported_config_tool_keys = set([
|
|
58
|
-
'exe', 'handlers',
|
|
58
|
+
'exe', 'docker_support', 'handlers',
|
|
59
59
|
'requires_env', 'requires_py', 'requires_cmd', 'requires_in_exe_path',
|
|
60
60
|
'requires_vsim_helper',
|
|
61
61
|
'requires_vscode_extension',
|
|
@@ -76,6 +76,7 @@ class Defaults:
|
|
|
76
76
|
'simulate-waivers',
|
|
77
77
|
'simulate-coverage-tcl',
|
|
78
78
|
'coverage-args',
|
|
79
|
+
'tcl-command-args',
|
|
79
80
|
])
|
|
80
81
|
|
|
81
82
|
EDA_OUTPUT_CONFIG_FNAME = 'eda_output_config.yml'
|
opencos/eda_config_defaults.yml
CHANGED
|
@@ -47,7 +47,7 @@ DEFAULT_HANDLERS_HELP:
|
|
|
47
47
|
targets: List all possible targets given glob path.
|
|
48
48
|
lec: Run equivalence on two designs.
|
|
49
49
|
deps-help: Provide help about DEPS markup files, or schema using --verbose or --help.
|
|
50
|
-
help: This help (without args), or i.e. "eda help
|
|
50
|
+
help: This help (without args), or i.e. "eda sim --help [--tool=TOOL]" for specific help.
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
|
|
@@ -270,6 +270,7 @@ tools:
|
|
|
270
270
|
|
|
271
271
|
verilator:
|
|
272
272
|
exe: verilator
|
|
273
|
+
docker_support: true
|
|
273
274
|
handlers:
|
|
274
275
|
lint: opencos.tools.verilator.VerilatorLint
|
|
275
276
|
elab: opencos.tools.verilator.VerilatorElab
|
|
@@ -682,9 +683,15 @@ tools:
|
|
|
682
683
|
requires_cmd:
|
|
683
684
|
- yosys -m slang
|
|
684
685
|
handlers:
|
|
686
|
+
flist: opencos.tools.slang_yosys.CommandFListSlangYosys
|
|
685
687
|
elab: opencos.tools.slang_yosys.CommandElabSlangYosys
|
|
686
688
|
synth: opencos.tools.slang_yosys.CommandSynthSlangYosys
|
|
687
689
|
lec: opencos.tools.slang_yosys.CommandLecSlangYosys
|
|
690
|
+
tcl-command-args:
|
|
691
|
+
read_slang:
|
|
692
|
+
- --ignore-unknown-modules
|
|
693
|
+
- --best-effort-hierarchy
|
|
694
|
+
- --ignore-timing
|
|
688
695
|
defines:
|
|
689
696
|
OC_TOOL_YOSYS: null
|
|
690
697
|
OC_TOOL_SLANG: null
|
|
@@ -717,5 +724,6 @@ tools:
|
|
|
717
724
|
requires_cmd:
|
|
718
725
|
- yosys
|
|
719
726
|
handlers:
|
|
727
|
+
flist: opencos.tools.slang_yosys.CommonFListYosys
|
|
720
728
|
synth: opencos.tools.slang_yosys.CommonSynthYosys
|
|
721
729
|
lec: opencos.tools.slang_yosys.CommandLecYosys
|