opencos-eda 0.3.10__py3-none-any.whl → 0.3.12__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 +4 -4
- opencos/commands/sim.py +14 -15
- opencos/commands/sweep.py +1 -1
- opencos/commands/synth.py +1 -2
- opencos/commands/upload.py +192 -4
- opencos/commands/waves.py +52 -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 +358 -155
- opencos/eda_base.py +187 -60
- opencos/eda_config.py +70 -35
- opencos/eda_config_defaults.yml +310 -186
- opencos/eda_config_reduced.yml +19 -39
- opencos/eda_tool_helper.py +190 -21
- opencos/files.py +26 -1
- opencos/tools/cocotb.py +11 -23
- opencos/tools/invio.py +2 -2
- opencos/tools/invio_yosys.py +2 -1
- opencos/tools/iverilog.py +3 -3
- opencos/tools/modelsim_ase.py +1 -1
- opencos/tools/quartus.py +172 -137
- opencos/tools/questa_common.py +50 -9
- opencos/tools/riviera.py +5 -4
- opencos/tools/slang.py +14 -10
- opencos/tools/slang_yosys.py +1 -0
- opencos/tools/surelog.py +7 -6
- opencos/tools/verilator.py +9 -7
- opencos/tools/vivado.py +315 -180
- opencos/tools/yosys.py +5 -5
- opencos/util.py +6 -3
- opencos/utils/dict_helpers.py +31 -0
- opencos/utils/markup_helpers.py +2 -2
- opencos/utils/str_helpers.py +38 -0
- 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.12.dist-info}/METADATA +1 -1
- opencos_eda-0.3.12.dist-info/RECORD +93 -0
- opencos/eda_config_max_verilator_waivers.yml +0 -39
- opencos_eda-0.3.10.dist-info/RECORD +0 -81
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.12.dist-info}/WHEEL +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.12.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.12.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.12.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.3.10.dist-info → opencos_eda-0.3.12.dist-info}/top_level.txt +0 -0
opencos/eda_tool_helper.py
CHANGED
|
@@ -10,8 +10,11 @@ Example uses:
|
|
|
10
10
|
|
|
11
11
|
'''
|
|
12
12
|
|
|
13
|
+
from importlib import import_module
|
|
13
14
|
|
|
14
|
-
from opencos import
|
|
15
|
+
from opencos import eda_config, util
|
|
16
|
+
from opencos.util import Colors
|
|
17
|
+
from opencos.utils import str_helpers
|
|
15
18
|
|
|
16
19
|
# Used by pytest, so we can skip tests if tools aren't present.
|
|
17
20
|
|
|
@@ -26,8 +29,13 @@ def get_config_and_tools_loaded( # pylint: disable=dangerous-default-value
|
|
|
26
29
|
# We have to figure out what tools are avaiable w/out calling eda.main,
|
|
27
30
|
# so we can get some of these using eda_config.get_eda_config()
|
|
28
31
|
config, _ = eda_config.get_eda_config(args=args, quiet=quiet)
|
|
32
|
+
|
|
33
|
+
# only import 'eda' here so that other methods in this pymodule can be used
|
|
34
|
+
# within eda, etc, if you already have a valid config or tools_loaded.
|
|
35
|
+
eda = import_module("opencos.eda")
|
|
29
36
|
config = eda.init_config(config=config, quiet=quiet)
|
|
30
37
|
tools_loaded = config.get('tools_loaded', set()).copy()
|
|
38
|
+
|
|
31
39
|
return config, tools_loaded
|
|
32
40
|
|
|
33
41
|
|
|
@@ -50,22 +58,27 @@ def get_all_handler_commands(config=None, tools_loaded=None) -> dict:
|
|
|
50
58
|
assert isinstance(tools_loaded, set)
|
|
51
59
|
|
|
52
60
|
# Let's re-walk auto_tools_order to get this ordered per eda command:
|
|
53
|
-
for
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
for command, tools_list in config.get('auto_tools_order', {}).items():
|
|
62
|
+
|
|
63
|
+
for tool in tools_list:
|
|
64
|
+
entry = config.get('tools', {}).get(tool, {})
|
|
65
|
+
assert entry, f'{command=} in auto_tools_order {tool=} not present in tools'
|
|
66
|
+
|
|
67
|
+
if tool not in tools_loaded:
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
if entry.get('disable-tools-multi', False):
|
|
71
|
+
# Flagged as do-not-add when running eda command: tools-multi
|
|
72
|
+
util.debug(f'eda_tool_helper.py -- skipping {tool=} it is set with flag',
|
|
73
|
+
'disable-tools-multi in config')
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
if command in entry.get('handlers', {}):
|
|
77
|
+
if command not in all_handler_commands:
|
|
78
|
+
# create ordered list from config.
|
|
79
|
+
all_handler_commands[command] = list([tool])
|
|
80
|
+
else:
|
|
81
|
+
all_handler_commands[command].append(tool)
|
|
69
82
|
|
|
70
83
|
return all_handler_commands
|
|
71
84
|
|
|
@@ -73,7 +86,7 @@ def get_all_handler_commands(config=None, tools_loaded=None) -> dict:
|
|
|
73
86
|
def get_handler_tool_version(tool: str, eda_command: str, config: dict) -> str:
|
|
74
87
|
'''Attempts to get a Command Handler's version given tool + eda_command'''
|
|
75
88
|
|
|
76
|
-
entry = config['
|
|
89
|
+
entry = config['tools'].get(tool, {})
|
|
77
90
|
if not entry:
|
|
78
91
|
return ''
|
|
79
92
|
|
|
@@ -83,7 +96,163 @@ def get_handler_tool_version(tool: str, eda_command: str, config: dict) -> str:
|
|
|
83
96
|
|
|
84
97
|
module = util.import_class_from_string(handler_name)
|
|
85
98
|
obj = module(config=config)
|
|
86
|
-
if not getattr(obj, 'get_versions', None):
|
|
87
|
-
return ''
|
|
88
99
|
|
|
89
|
-
|
|
100
|
+
# Some command classes like CommandWaves, don't have get_versions(), but
|
|
101
|
+
# have get_versions_of_tool():
|
|
102
|
+
if getattr(obj, 'get_versions_of_tool', None):
|
|
103
|
+
return obj.get_versions_of_tool(tool)
|
|
104
|
+
|
|
105
|
+
# Note that Tool.get_versions() is supposed to be 'fast', we don't always
|
|
106
|
+
# run the tool if the 'exe -version' takes too long.
|
|
107
|
+
if getattr(obj, 'get_versions', None):
|
|
108
|
+
return obj.get_versions()
|
|
109
|
+
|
|
110
|
+
return ''
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def get_handler_info_with_versions( # pylint: disable=too-many-branches
|
|
115
|
+
config: dict | None = None,
|
|
116
|
+
include_commands: bool = True,
|
|
117
|
+
sort: bool = True
|
|
118
|
+
) -> str:
|
|
119
|
+
'''Creates and returns a dict of
|
|
120
|
+
|
|
121
|
+
{'commands': (what tools/versions can run them),
|
|
122
|
+
'tools': (what version and what commands they can run)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for arg 'config' you may use:
|
|
126
|
+
|
|
127
|
+
config, tools_loaded = get_config_and_tools_loaded()
|
|
128
|
+
'''
|
|
129
|
+
|
|
130
|
+
if not config:
|
|
131
|
+
config, tools_loaded = get_config_and_tools_loaded()
|
|
132
|
+
else:
|
|
133
|
+
tools_loaded = list(config.get('tools_loaded', set()))
|
|
134
|
+
|
|
135
|
+
eda_commands = list(config.get('DEFAULT_HANDLERS', {}).keys())
|
|
136
|
+
show_versions = config.get('show_tool_versions', False)
|
|
137
|
+
|
|
138
|
+
info = {
|
|
139
|
+
'tools': {},
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if not show_versions:
|
|
144
|
+
for tool, path in config.get('auto_tools_found', {}).items():
|
|
145
|
+
info['tools'][tool] = {
|
|
146
|
+
'path': path
|
|
147
|
+
}
|
|
148
|
+
return info
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if include_commands:
|
|
152
|
+
info.update({
|
|
153
|
+
'commands': {}
|
|
154
|
+
})
|
|
155
|
+
for eda_command in eda_commands:
|
|
156
|
+
info['commands'][eda_command] = {} # init
|
|
157
|
+
|
|
158
|
+
for tool in tools_loaded:
|
|
159
|
+
|
|
160
|
+
if include_commands:
|
|
161
|
+
info['tools'][tool] = {
|
|
162
|
+
'version': '',
|
|
163
|
+
'commands': [],
|
|
164
|
+
}
|
|
165
|
+
else:
|
|
166
|
+
info['tools'][tool] = {
|
|
167
|
+
'version': '',
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for eda_command in eda_commands:
|
|
171
|
+
|
|
172
|
+
if not include_commands and info['tools'][tool]['version']:
|
|
173
|
+
# version is already set, and we're not doing for all commands:
|
|
174
|
+
break
|
|
175
|
+
|
|
176
|
+
# Note that if you have a generic handler, or a tool that has
|
|
177
|
+
# several handlers with more than one Tool class, that all can return a
|
|
178
|
+
# non blank-str version, you may have problems.
|
|
179
|
+
ver = get_handler_tool_version(
|
|
180
|
+
tool=tool, eda_command=eda_command, config=config
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
if not ver:
|
|
184
|
+
continue
|
|
185
|
+
|
|
186
|
+
info['tools'][tool]['version'] = ver
|
|
187
|
+
|
|
188
|
+
if include_commands:
|
|
189
|
+
info['commands'][eda_command][tool] = ver
|
|
190
|
+
info['tools'][tool]['commands'].append(eda_command)
|
|
191
|
+
|
|
192
|
+
for tool, _ in info['tools'].items():
|
|
193
|
+
if tool in config.get('auto_tools_found', {}):
|
|
194
|
+
info['tools'][tool]['path'] = config['auto_tools_found'][tool]
|
|
195
|
+
|
|
196
|
+
# return the info dict with 'tools' and 'commands' entries sorted:
|
|
197
|
+
if sort:
|
|
198
|
+
for key in list(info.keys()):
|
|
199
|
+
if info[key]:
|
|
200
|
+
info[key] = dict(sorted(info[key].items()))
|
|
201
|
+
|
|
202
|
+
return info
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def pretty_info_handler_tools(
|
|
206
|
+
info: dict | None = None, config: dict | None = None, command: str | None = ''
|
|
207
|
+
) -> None:
|
|
208
|
+
'''Pretty print (via util.info) the result from get_handler_info_with_versions()
|
|
209
|
+
|
|
210
|
+
if info is None or empty, will use config to run get_handler_info_with_versions(..)
|
|
211
|
+
|
|
212
|
+
Does not include commands
|
|
213
|
+
'''
|
|
214
|
+
|
|
215
|
+
if not info:
|
|
216
|
+
info = get_handler_info_with_versions(config=config, include_commands=False, sort=True)
|
|
217
|
+
|
|
218
|
+
if not info.get('tools', {}):
|
|
219
|
+
# No tools detected
|
|
220
|
+
if command and command in config.get('command_tool_is_optional', []):
|
|
221
|
+
# but this command doesn't need tools
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
# if command omitted, or command may need tools, print that we don't have any
|
|
225
|
+
util.info('No tools detected!', color=Colors.yellow)
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
show_versions = any('version' in dvalue for dvalue in info['tools'].values())
|
|
229
|
+
|
|
230
|
+
tools_rows = [
|
|
231
|
+
['--Detected tool--', '--Path--'] # Header row.
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
if show_versions:
|
|
235
|
+
tools_rows[0].append('--Version--')
|
|
236
|
+
|
|
237
|
+
for _tool, dvalue in info['tools'].items():
|
|
238
|
+
path = dvalue.get("path", "")
|
|
239
|
+
if path:
|
|
240
|
+
path = f'({path})'
|
|
241
|
+
|
|
242
|
+
if show_versions:
|
|
243
|
+
version = dvalue.get("version", "")
|
|
244
|
+
# will defer printing again, so we can put them into aligned columns:
|
|
245
|
+
tools_rows.append([_tool, path, version])
|
|
246
|
+
else:
|
|
247
|
+
tools_rows.append([_tool, path])
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# Finally, print detected tools:
|
|
251
|
+
for rownum, row in enumerate(str_helpers.pretty_2dlist_columns(
|
|
252
|
+
tools_rows, return_as_2d_list=True, header_row_centered=False)):
|
|
253
|
+
if rownum == 0:
|
|
254
|
+
util.info(f'{Colors.bgreen}{"".join(row)}')
|
|
255
|
+
else:
|
|
256
|
+
# get the results in a padded 2D list so we can colorize the tool (index 0)
|
|
257
|
+
util.info(f'{Colors.bgreen}{row[0]}{Colors.normal}{Colors.cyan}' \
|
|
258
|
+
+ ''.join(row[1:]))
|
opencos/files.py
CHANGED
|
@@ -13,6 +13,7 @@ as part of a verilog $readmemh, etc)
|
|
|
13
13
|
'''
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
|
+
import shutil
|
|
16
17
|
|
|
17
18
|
# Ways to force files not ending in .sv to be systemverilog (for tools
|
|
18
19
|
# that require -sv vs Verilog-2001'''
|
|
@@ -31,8 +32,12 @@ FORCE_PREFIX_DICT = {
|
|
|
31
32
|
|
|
32
33
|
ALL_FORCED_PREFIXES = set(list(FORCE_PREFIX_DICT.keys()))
|
|
33
34
|
|
|
34
|
-
def get_source_file(target:str) -> (bool, str, str):
|
|
35
|
+
def get_source_file(target: str) -> (bool, str, str):
|
|
35
36
|
'''Returns tuple: bool if file exists, filepath str, and optional forced file type str'''
|
|
37
|
+
|
|
38
|
+
if '$' in target:
|
|
39
|
+
target = os.path.expandvars(target)
|
|
40
|
+
|
|
36
41
|
if os.path.isfile(target):
|
|
37
42
|
# target exists as a file, return True w/ original target:
|
|
38
43
|
return True, target, ''
|
|
@@ -47,3 +52,23 @@ def get_source_file(target:str) -> (bool, str, str):
|
|
|
47
52
|
|
|
48
53
|
# target or fpath didn't exist, return False with the original target:
|
|
49
54
|
return False, target, ''
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def safe_shutil_which(path: str) -> str:
|
|
58
|
+
'''Windows/WSL compatible Wrapper for shutil.which that checks for 'path':
|
|
59
|
+
|
|
60
|
+
- path
|
|
61
|
+
- path.exe
|
|
62
|
+
- path.bat
|
|
63
|
+
|
|
64
|
+
Returns full path str returned by shutil.which
|
|
65
|
+
'''
|
|
66
|
+
for ext in ('', '.exe', 'bat'):
|
|
67
|
+
if found := shutil.which(f'{path}{ext}'):
|
|
68
|
+
return found
|
|
69
|
+
return ''
|
|
70
|
+
|
|
71
|
+
# Note that in Windows, 'python' will return the venv or uv version, 'python3' will
|
|
72
|
+
# return the installed version (which may not be what you want), so we'll prefer
|
|
73
|
+
# 'python':
|
|
74
|
+
PY_EXE = safe_shutil_which('python') or safe_shutil_which('python3')
|
opencos/tools/cocotb.py
CHANGED
|
@@ -4,12 +4,12 @@ Contains classes for ToolCocotb, CommandSimCocotb.
|
|
|
4
4
|
'''
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
|
-
import
|
|
8
|
-
import subprocess
|
|
7
|
+
from importlib import metadata
|
|
9
8
|
|
|
10
9
|
from opencos import util
|
|
11
|
-
from opencos.eda_base import Tool
|
|
12
10
|
from opencos.commands import CommandSim
|
|
11
|
+
from opencos.eda_base import Tool
|
|
12
|
+
from opencos.files import safe_shutil_which, PY_EXE
|
|
13
13
|
from opencos.utils import status_constants
|
|
14
14
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
15
15
|
from opencos.tools import verilator # For default waivers.
|
|
@@ -30,7 +30,7 @@ class ToolCocotb(Tool):
|
|
|
30
30
|
return self._VERSION
|
|
31
31
|
|
|
32
32
|
# Check if python is available
|
|
33
|
-
python_path =
|
|
33
|
+
python_path = PY_EXE
|
|
34
34
|
if not python_path:
|
|
35
35
|
self.error('"python" or "python3" not in path, required for cocotb')
|
|
36
36
|
else:
|
|
@@ -38,22 +38,16 @@ class ToolCocotb(Tool):
|
|
|
38
38
|
|
|
39
39
|
# Check if cocotb is installed
|
|
40
40
|
try:
|
|
41
|
-
|
|
42
|
-
[self.python_exe, '-c', 'import cocotb; print(cocotb.__version__)'],
|
|
43
|
-
capture_output=True,
|
|
44
|
-
check=True,
|
|
45
|
-
text=True
|
|
46
|
-
)
|
|
47
|
-
version = version_ret.stdout.strip()
|
|
41
|
+
version = metadata.version('cocotb')
|
|
48
42
|
self.cocotb_version = version
|
|
49
43
|
self._VERSION = version
|
|
50
44
|
util.debug(f'Found cocotb version: {version}')
|
|
51
45
|
return self._VERSION
|
|
52
|
-
except
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
except metadata.PackageNotFoundError:
|
|
47
|
+
util.warning('cocotb package not installed in python environment. '
|
|
48
|
+
'Install with: pip install cocotb; or pypackage: opencos-eda[cocotb]')
|
|
55
49
|
except Exception as e:
|
|
56
|
-
|
|
50
|
+
util.warning(f'Failed to check cocotb version: {e}')
|
|
57
51
|
|
|
58
52
|
return ''
|
|
59
53
|
|
|
@@ -128,7 +122,7 @@ class CommandSimCocotb(CommandSim, ToolCocotb):
|
|
|
128
122
|
util.warning('--cocotb-simulator is not set, a simulation cannot be run with'
|
|
129
123
|
'this arg value')
|
|
130
124
|
return
|
|
131
|
-
exe =
|
|
125
|
+
exe = safe_shutil_which(simulator)
|
|
132
126
|
if not exe:
|
|
133
127
|
util.warning(f'--cocotb-simulator={simulator}, {simulator} is not present in PATH',
|
|
134
128
|
'a simulation cannot be run with this arg value')
|
|
@@ -330,13 +324,7 @@ class CommandSimCocotb(CommandSim, ToolCocotb):
|
|
|
330
324
|
def _generate_runner_script_content(self, test_module: str, hdl_sources: list) -> str:
|
|
331
325
|
'''Generate the content for the Python runner script'''
|
|
332
326
|
|
|
333
|
-
if
|
|
334
|
-
# TODO(drew): this shortcuts if verilator is truly usable,
|
|
335
|
-
# consider using eda_tool_helper to get "tools_loaded", which
|
|
336
|
-
# is not set in self.config['tools_loaded'] when --tool=cocotb.
|
|
337
|
-
# Would need minor refactor for eda.py methods auto_tools_order,
|
|
338
|
-
# tool_setup to go into eda_tool_helper.py, and those methods would
|
|
339
|
-
# need hooks to be non-destructive to config.
|
|
327
|
+
if safe_shutil_which('verilator'):
|
|
340
328
|
tmp_verilator_obj = verilator.VerilatorSim(config=self.config)
|
|
341
329
|
verilator_waivers = tmp_verilator_obj.get_verilator_tool_config_waivers()
|
|
342
330
|
else:
|
opencos/tools/invio.py
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
import importlib.util
|
|
6
6
|
|
|
7
7
|
from opencos import util
|
|
8
|
-
from opencos.tools import invio_helpers
|
|
9
|
-
from opencos.eda_base import Tool
|
|
10
8
|
from opencos.commands import CommandElab
|
|
9
|
+
from opencos.eda_base import Tool
|
|
10
|
+
from opencos.tools import invio_helpers
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
opencos/tools/invio_yosys.py
CHANGED
|
@@ -8,6 +8,7 @@ import os
|
|
|
8
8
|
import importlib.util
|
|
9
9
|
|
|
10
10
|
from opencos import util
|
|
11
|
+
from opencos.files import PY_EXE
|
|
11
12
|
from opencos.tools import invio_helpers
|
|
12
13
|
from opencos.tools.yosys import ToolYosys, CommonSynthYosys
|
|
13
14
|
|
|
@@ -100,7 +101,7 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
|
|
|
100
101
|
|
|
101
102
|
|
|
102
103
|
invio_command_list = util.ShellCommandList(
|
|
103
|
-
[
|
|
104
|
+
[PY_EXE, invio_dict['full_py_filename']], tee_fpath=invio_dict['full_py_filename']
|
|
104
105
|
)
|
|
105
106
|
|
|
106
107
|
# Optinally create and run a sta.f:
|
opencos/tools/iverilog.py
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
Contains classes for ToolIverilog CommandSimIverilog, CommandElabIverilog.
|
|
4
4
|
'''
|
|
5
5
|
|
|
6
|
-
import shutil
|
|
7
6
|
import subprocess
|
|
8
7
|
|
|
9
8
|
from opencos import util
|
|
10
|
-
from opencos.eda_base import Tool
|
|
11
9
|
from opencos.commands import CommandSim
|
|
10
|
+
from opencos.eda_base import Tool
|
|
11
|
+
from opencos.files import safe_shutil_which
|
|
12
12
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
13
13
|
|
|
14
14
|
|
|
@@ -28,7 +28,7 @@ class ToolIverilog(Tool):
|
|
|
28
28
|
if self._VERSION:
|
|
29
29
|
return self._VERSION
|
|
30
30
|
|
|
31
|
-
iverilog_path =
|
|
31
|
+
iverilog_path = safe_shutil_which(self._EXE)
|
|
32
32
|
if iverilog_path is None:
|
|
33
33
|
self.error(f'"{self._EXE}" not in path, need to get it ({self._URL})')
|
|
34
34
|
else:
|
opencos/tools/modelsim_ase.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
''' opencos.tools.modelsim_ase - Used by opencos.eda for sim/elab commands w/ --tool=modelsim_ase.
|
|
2
2
|
|
|
3
|
-
Contains classes for
|
|
3
|
+
Contains classes for CommandSimModelsimAse, CommandElabModelsimAse.
|
|
4
4
|
|
|
5
5
|
Note that this is for 32-bit Modelsim Student Edition. Consider using --tool=questa_fse instead.
|
|
6
6
|
'''
|