opencos-eda 0.3.7__tar.gz → 0.3.8__tar.gz
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_eda-0.3.7/opencos_eda.egg-info → opencos_eda-0.3.8}/PKG-INFO +1 -1
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/sim.py +61 -11
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_base.py +77 -18
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_config.py +1 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_config_defaults.yml +28 -3
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_tools.py +53 -30
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/iverilog.py +2 -2
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/riviera.py +33 -2
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/slang.py +24 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/surelog.py +22 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/verilator.py +11 -5
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/vivado.py +4 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/util.py +2 -1
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/utils/str_helpers.py +4 -4
- {opencos_eda-0.3.7 → opencos_eda-0.3.8/opencos_eda.egg-info}/PKG-INFO +1 -1
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/pyproject.toml +1 -1
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/LICENSE +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/LICENSE.spdx +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/README.md +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/__init__.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/_version.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/_waves_pkg.sv +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/__init__.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/build.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/deps_help.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/elab.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/export.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/flist.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/lec.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/lint.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/multi.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/open.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/proj.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/shell.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/sweep.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/synth.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/targets.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/upload.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/commands/waves.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/deps/__init__.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/deps/defaults.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/deps/deps_commands.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/deps/deps_file.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/deps/deps_processor.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/deps_schema.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_config_max_verilator_waivers.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_config_reduced.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_deps_bash_completion.bash +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_deps_sanitize.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_extract_targets.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/eda_tool_helper.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/export_helper.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/export_json_convert.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/files.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/hw/__init__.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/hw/oc_cli.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/hw/pcie.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/names.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/peakrdl_cleanup.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/seed.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/__init__.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/custom_config.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/helpers.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_build.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_deps_helpers.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_deps_schema.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_eda.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_eda_elab.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_eda_synth.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tests/test_oc_cli.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/__init__.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/cocotb.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/invio.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/invio_helpers.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/invio_yosys.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/modelsim_ase.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/quartus.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/questa.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/questa_fse.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/slang_yosys.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/tabbycad_yosys.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/tools/yosys.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/utils/__init__.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/utils/markup_helpers.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/utils/status_constants.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/utils/subprocess_helpers.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/utils/vscode_helper.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos/utils/vsim_helper.py +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos_eda.egg-info/SOURCES.txt +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos_eda.egg-info/dependency_links.txt +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos_eda.egg-info/entry_points.txt +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos_eda.egg-info/requires.txt +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/opencos_eda.egg-info/top_level.txt +0 -0
- {opencos_eda-0.3.7 → opencos_eda-0.3.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: A simple Python package for wrapping RTL simuliatons and synthesis
|
|
5
5
|
Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/cognichip/opencos
|
|
@@ -44,7 +44,7 @@ def parameters_dict_get_command_list(params: dict, arg_prefix: str = '-G') -> li
|
|
|
44
44
|
return ret_list
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
class CommandSim(CommandDesign):
|
|
47
|
+
class CommandSim(CommandDesign): # pylint: disable=too-many-public-methods
|
|
48
48
|
'''Base class command handler for: eda sim ...'''
|
|
49
49
|
|
|
50
50
|
CHECK_REQUIRES = [Tool] # Used by check_command_handler_cls()
|
|
@@ -72,6 +72,9 @@ class CommandSim(CommandDesign):
|
|
|
72
72
|
'optimize': False,
|
|
73
73
|
'log-bad-strings': ['ERROR: ', 'FATAL: ', 'Error: ', 'Fatal: '],
|
|
74
74
|
'log-must-strings': [],
|
|
75
|
+
'log-warning-strings': ['WARNING: ', 'Warning: '],
|
|
76
|
+
'uvm': False,
|
|
77
|
+
'uvm-version': '1.2',
|
|
75
78
|
# verilate-args: list of args you can only pass to Verilator,
|
|
76
79
|
# not used by other simulators, so these can go in DEPS files for custom things
|
|
77
80
|
# like -CFLAGS -O0, etc.
|
|
@@ -91,6 +94,8 @@ class CommandSim(CommandDesign):
|
|
|
91
94
|
'log-must-strings': ('strings that are required by the log to not-fail the simulation.'
|
|
92
95
|
' Some tools use these at only certain phases'
|
|
93
96
|
' (compile/elab/sim).'),
|
|
97
|
+
'log-warning-strings': ('strings that if present will be counted in the total tool'
|
|
98
|
+
' warnings at end of simulation'),
|
|
94
99
|
'pass-pattern': ('Additional string required to pass a simulation, appends to'
|
|
95
100
|
' log-must-strings'),
|
|
96
101
|
'sim-args': 'args added to final "simulation" step',
|
|
@@ -111,12 +116,22 @@ class CommandSim(CommandDesign):
|
|
|
111
116
|
'waves': 'Include waveforms, if possible for tool',
|
|
112
117
|
'waves-start': 'Starting time of waveform capture, if possible for tool',
|
|
113
118
|
'test-mode': ('stops the command early without executing, if --gui is present will'
|
|
114
|
-
' instead test without spawning gui')
|
|
119
|
+
' instead test without spawning gui'),
|
|
120
|
+
'uvm': (
|
|
121
|
+
'Attempts to support UVM (aka 1.2 if --uvm-version=1.2) for the'
|
|
122
|
+
' the simulation tool. May add libraries for uvm, tool dependent.'
|
|
123
|
+
),
|
|
124
|
+
'uvm-version': (
|
|
125
|
+
'Used if --uvm is set, for example --uvm-version=1.2'
|
|
126
|
+
),
|
|
127
|
+
|
|
128
|
+
})
|
|
115
129
|
|
|
130
|
+
self.args_kwargs.update({
|
|
131
|
+
'uvm-version': { 'choices': ['1.2'] },
|
|
116
132
|
})
|
|
117
133
|
|
|
118
134
|
|
|
119
|
-
self.args['verilate-args'] = []
|
|
120
135
|
|
|
121
136
|
def process_parameters_get_list(self, arg_prefix: str = '-G') -> list:
|
|
122
137
|
'''Returns list (suitable command list for shell or for tool) from self.parameters'''
|
|
@@ -182,14 +197,14 @@ class CommandSim(CommandDesign):
|
|
|
182
197
|
|
|
183
198
|
# Collect (overwrite CommandSim) the bad and must strings, if present,
|
|
184
199
|
# from our config.tools.verilator:
|
|
185
|
-
for tool_config_key in
|
|
200
|
+
for tool_config_key in ('log-bad-strings', 'log-must-strings', 'log-warning-strings'):
|
|
186
201
|
if len(self.tool_config.get(tool_config_key, [])) > 0:
|
|
187
202
|
self.args[tool_config_key] = self.tool_config.get(tool_config_key, [])
|
|
188
203
|
|
|
189
204
|
|
|
190
205
|
# Methods that derived classes may override:
|
|
191
206
|
|
|
192
|
-
def run_commands_check_logs( # pylint: disable=dangerous-default-value
|
|
207
|
+
def run_commands_check_logs( # pylint: disable=dangerous-default-value,too-many-locals
|
|
193
208
|
self, commands: list , check_logs: bool = True, log_filename=None,
|
|
194
209
|
bad_strings: list = [],
|
|
195
210
|
must_strings: list = [],
|
|
@@ -197,7 +212,10 @@ class CommandSim(CommandDesign):
|
|
|
197
212
|
) -> None:
|
|
198
213
|
'''Returns None, runs all commands (each element is a list) and checks logs
|
|
199
214
|
|
|
200
|
-
for bad-strings and must-strings (args or class member vars)
|
|
215
|
+
for bad-strings and must-strings (args or class member vars).
|
|
216
|
+
|
|
217
|
+
Will add any bad_strings or tool log-warning-strings to self, so tool
|
|
218
|
+
related warning/error counts can be reported later.
|
|
201
219
|
'''
|
|
202
220
|
|
|
203
221
|
for obj in commands:
|
|
@@ -212,7 +230,7 @@ class CommandSim(CommandDesign):
|
|
|
212
230
|
if not work_dir:
|
|
213
231
|
work_dir = self.args['work-dir']
|
|
214
232
|
|
|
215
|
-
util.debug(f'run_commands_check_logs: {clist=}, {tee_fpath=}')
|
|
233
|
+
util.debug(f'run_commands_check_logs: {clist=}, {tee_fpath=}, {log_filename=}')
|
|
216
234
|
|
|
217
235
|
log_fname = None
|
|
218
236
|
if tee_fpath:
|
|
@@ -220,11 +238,18 @@ class CommandSim(CommandDesign):
|
|
|
220
238
|
if log_filename:
|
|
221
239
|
log_fname = log_filename
|
|
222
240
|
|
|
223
|
-
|
|
224
|
-
_, stdout,
|
|
225
|
-
work_dir=work_dir, command_list=clist, tee_fpath=tee_fpath
|
|
241
|
+
# track the retcode because we run stop_on_error=False (to count warnings/errors)
|
|
242
|
+
_, stdout, retcode = self.exec(
|
|
243
|
+
work_dir=work_dir, command_list=clist, tee_fpath=tee_fpath,
|
|
244
|
+
stop_on_error=False,
|
|
226
245
|
)
|
|
227
246
|
|
|
247
|
+
if check_logs and not log_fname and bad_strings:
|
|
248
|
+
util.warning(
|
|
249
|
+
f'{self.get_info_job_name()}: check_logs=True but no log file set',
|
|
250
|
+
f'(run --debug for more info), for command: {" ".join(clist)}'
|
|
251
|
+
)
|
|
252
|
+
|
|
228
253
|
if check_logs and log_fname:
|
|
229
254
|
# Note this call will check on stdout if not GUI, not opening the log_fname,
|
|
230
255
|
# but if this is GUI we normally lose stdout and have to open the log.
|
|
@@ -234,6 +259,7 @@ class CommandSim(CommandDesign):
|
|
|
234
259
|
file_contents_str = stdout
|
|
235
260
|
|
|
236
261
|
self.check_logs_for_errors(
|
|
262
|
+
sim_retcode=retcode,
|
|
237
263
|
filename=os.path.join(work_dir, log_fname),
|
|
238
264
|
file_contents_str=file_contents_str,
|
|
239
265
|
bad_strings=bad_strings, must_strings=must_strings,
|
|
@@ -244,6 +270,10 @@ class CommandSim(CommandDesign):
|
|
|
244
270
|
name=os.path.join(work_dir, log_fname),
|
|
245
271
|
typ='text', description='Simulator stdout/stderr log file'
|
|
246
272
|
)
|
|
273
|
+
if retcode:
|
|
274
|
+
self.error(
|
|
275
|
+
f"{self.get_info_job_name()}: exec returned with error code: {retcode}"
|
|
276
|
+
)
|
|
247
277
|
|
|
248
278
|
def do_export(self) -> None:
|
|
249
279
|
'''CommandSim helper for handling args --export*
|
|
@@ -337,9 +367,13 @@ class CommandSim(CommandDesign):
|
|
|
337
367
|
'''
|
|
338
368
|
return
|
|
339
369
|
|
|
370
|
+
|
|
340
371
|
def check_logs_for_errors( # pylint: disable=dangerous-default-value,too-many-locals,too-many-branches
|
|
341
|
-
self,
|
|
372
|
+
self,
|
|
373
|
+
sim_retcode: int = 0,
|
|
374
|
+
filename: str = '', file_contents_str: str = '',
|
|
342
375
|
bad_strings: list = [], must_strings: list = [],
|
|
376
|
+
warning_strings: list = [],
|
|
343
377
|
use_bad_strings: bool = True, use_must_strings: bool = True
|
|
344
378
|
) -> None:
|
|
345
379
|
'''Returns None, checks logs using args bad_strings, must_strings,
|
|
@@ -358,6 +392,8 @@ class CommandSim(CommandDesign):
|
|
|
358
392
|
if use_must_strings:
|
|
359
393
|
_must_strings = must_strings + self.args.get('log-must-strings', [])
|
|
360
394
|
|
|
395
|
+
_warning_strings = warning_strings + self.args.get('log-warning-strings', [])
|
|
396
|
+
|
|
361
397
|
if self.args['pass-pattern'] != "":
|
|
362
398
|
_must_strings.append(self.args['pass-pattern'])
|
|
363
399
|
|
|
@@ -389,6 +425,20 @@ class CommandSim(CommandDesign):
|
|
|
389
425
|
self.error(f'sim.check_logs_for_errors: {log_fpath=} does not exist, and no',
|
|
390
426
|
'file_contents_str exists to check')
|
|
391
427
|
|
|
428
|
+
self.update_tool_warn_err_counts_from_log_lines(
|
|
429
|
+
log_lines=lines, bad_strings=_bad_strings, warning_strings=_warning_strings
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
if isinstance(self, Tool):
|
|
433
|
+
self.report_tool_warn_error_counts()
|
|
434
|
+
|
|
435
|
+
if sim_retcode > 0:
|
|
436
|
+
# We have to update artifacts first, have the caller set the error.
|
|
437
|
+
# Skip the checking for bad strings or must strings, because we've already
|
|
438
|
+
# failed, but we did the important counting of Error and Warning lines above,
|
|
439
|
+
# and reported it.
|
|
440
|
+
return
|
|
441
|
+
|
|
392
442
|
if lines:
|
|
393
443
|
for lineno, line in enumerate(lines):
|
|
394
444
|
if any(must_str in line for must_str in _must_strings):
|
|
@@ -178,6 +178,10 @@ class Tool:
|
|
|
178
178
|
# a Command object's self.args instead of the class Tool.args. Safely create it
|
|
179
179
|
# if it doesn't exist:
|
|
180
180
|
self._VERSION = None
|
|
181
|
+
|
|
182
|
+
self.tool_warning_count = 0
|
|
183
|
+
self.tool_error_count = 0
|
|
184
|
+
|
|
181
185
|
if getattr(self, 'args', None) is None:
|
|
182
186
|
self.args = {}
|
|
183
187
|
if getattr(self, 'args_help', None) is None:
|
|
@@ -225,12 +229,30 @@ class Tool:
|
|
|
225
229
|
'''Sets and returns self._VERSION'''
|
|
226
230
|
return self._VERSION
|
|
227
231
|
|
|
232
|
+
def report_tool_warn_error_counts(self) -> None:
|
|
233
|
+
'''Reports info line based on self.tool_error_count and self.tool_warning_count.'''
|
|
234
|
+
tool_name = get_class_tool_name(self)
|
|
235
|
+
if not tool_name:
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
info_color = Colors.green
|
|
239
|
+
start = ''
|
|
240
|
+
if self.tool_error_count or self.tool_warning_count:
|
|
241
|
+
start = safe_emoji('🔶 ')
|
|
242
|
+
info_color = Colors.yellow
|
|
243
|
+
util.info(
|
|
244
|
+
f"{start}Tool - {tool_name}, total counts:",
|
|
245
|
+
f"{Colors.bold}{self.tool_warning_count} tool warnings{Colors.normal}{info_color},",
|
|
246
|
+
f"{Colors.bold}{self.tool_error_count} tool errors",
|
|
247
|
+
color=info_color
|
|
248
|
+
)
|
|
249
|
+
|
|
228
250
|
def set_tool_defines(self) -> None:
|
|
229
251
|
'''Derived classes may override, sets any additional defines based on tool.'''
|
|
230
252
|
return
|
|
231
253
|
|
|
232
254
|
|
|
233
|
-
class Command: # pylint: disable=too-many-public-methods
|
|
255
|
+
class Command: # pylint: disable=too-many-public-methods,too-many-instance-attributes
|
|
234
256
|
'''Base class for all: eda COMMAND
|
|
235
257
|
|
|
236
258
|
The Command class should be used when you don't require files, otherwise consider
|
|
@@ -244,6 +266,8 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
244
266
|
self.args = {}
|
|
245
267
|
if getattr(self, 'args_help', None) is None:
|
|
246
268
|
self.args_help = {}
|
|
269
|
+
if getattr(self, 'args_kwargs', None) is None:
|
|
270
|
+
self.args_kwargs = {}
|
|
247
271
|
self.args.update({
|
|
248
272
|
"keep" : False,
|
|
249
273
|
"force" : False,
|
|
@@ -332,6 +356,13 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
332
356
|
self.tool_changed_respawn = {}
|
|
333
357
|
|
|
334
358
|
|
|
359
|
+
def get_info_job_name(self) -> str:
|
|
360
|
+
'''Returns an informational string of the job name, using: command - tool - top'''
|
|
361
|
+
return ' - '.join(
|
|
362
|
+
x for x in (self.command_name, self.args.get('tool', ''),
|
|
363
|
+
self.args.get('top', '')) if x
|
|
364
|
+
)
|
|
365
|
+
|
|
335
366
|
def error(self, *args, **kwargs) -> None:
|
|
336
367
|
'''Returns None, child classes can call self.error(..) instead of util.error,
|
|
337
368
|
|
|
@@ -359,7 +390,6 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
359
390
|
f'ERROR: [eda] ({self.command_name}) {" ".join(list(args))}',
|
|
360
391
|
file=self.errors_log_f
|
|
361
392
|
)
|
|
362
|
-
|
|
363
393
|
self.status = util.error(*args, **kwargs) # error_code passed and returned via kwargs
|
|
364
394
|
|
|
365
395
|
def stop_process_tokens_before_do_it(self) -> bool:
|
|
@@ -374,24 +404,28 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
374
404
|
return True
|
|
375
405
|
return False
|
|
376
406
|
|
|
377
|
-
def status_any_error(self, report=True) -> bool:
|
|
407
|
+
def status_any_error(self, report: bool = True) -> bool:
|
|
378
408
|
'''Used by derived classes process_tokens() to know an error was reached
|
|
379
|
-
and to not perform the command. Necessary for pytests that use eda.main()
|
|
380
|
-
|
|
409
|
+
and to not perform the command. Necessary for pytests that use eda.main()
|
|
410
|
+
|
|
411
|
+
Note we also check any parent Tool class for tool_error_count > 0
|
|
412
|
+
'''
|
|
413
|
+
any_err = False
|
|
414
|
+
if self.status > 0:
|
|
415
|
+
any_err = True
|
|
416
|
+
elif isinstance(self, Tool) and getattr(self, 'tool_error_count', 0):
|
|
417
|
+
util.warning(f'eda_base.py internal: Command status={self.status}, but',
|
|
418
|
+
f'Tool tool_error_count={getattr(self, "tool_error_count", 0)}')
|
|
419
|
+
any_err = True
|
|
420
|
+
if report and any_err:
|
|
381
421
|
util.error(f"command '{self.command_name}' has previous errors")
|
|
382
|
-
return
|
|
422
|
+
return any_err
|
|
383
423
|
|
|
384
424
|
def report_pass_fail(self) -> None:
|
|
385
425
|
'''Reports an INFO line with pass/fail information'''
|
|
386
|
-
job_name =
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
)
|
|
390
|
-
if self.status_any_error():
|
|
391
|
-
util.info(f'{safe_emoji("❌ ")}{job_name}: Errors observed.', color=Colors.red)
|
|
392
|
-
else:
|
|
393
|
-
util.info(f'{safe_emoji("✅ ")}{job_name}: No errors observed.')
|
|
394
|
-
|
|
426
|
+
job_name = self.get_info_job_name()
|
|
427
|
+
if not self.status_any_error():
|
|
428
|
+
util.info(f'{safe_emoji("✅ ")}{job_name}: {Colors.bold}No errors observed.')
|
|
395
429
|
|
|
396
430
|
def which_tool(self, command:str) -> str:
|
|
397
431
|
'''Returns a str for the tool name used for the requested command'''
|
|
@@ -557,16 +591,17 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
557
591
|
if return_code > 0:
|
|
558
592
|
if return_code == 1:
|
|
559
593
|
self.status = status_constants.EDA_EXEC_NONZERO_RETURN_CODE1
|
|
560
|
-
|
|
594
|
+
elif return_code == 255:
|
|
561
595
|
self.status = status_constants.EDA_EXEC_NONZERO_RETURN_CODE255
|
|
562
596
|
else:
|
|
563
597
|
self.status = status_constants.EDA_EXEC_NONZERO_RETURN_CODE2
|
|
598
|
+
|
|
564
599
|
if stop_on_error:
|
|
565
600
|
self.error(f"exec: returned with error (return code: {return_code})",
|
|
566
601
|
error_code=self.status)
|
|
567
602
|
else:
|
|
568
|
-
util.
|
|
569
|
-
|
|
603
|
+
util.info(f"{safe_emoji('❌ ')}exec: returned with error (return code:",
|
|
604
|
+
f"{return_code})")
|
|
570
605
|
else:
|
|
571
606
|
util.debug(f"exec: returned without error (return code: {return_code})")
|
|
572
607
|
return stderr, stdout, return_code
|
|
@@ -680,6 +715,10 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
680
715
|
help_kwargs = {'help': f'{type(value).__name__} default={value}'}
|
|
681
716
|
help_kwargs['help'] = help_kwargs['help'].replace('%', '%%')
|
|
682
717
|
|
|
718
|
+
# Update with any self.args_kwargs for this key
|
|
719
|
+
if self.args_kwargs.get(key, {}):
|
|
720
|
+
help_kwargs.update(self.args_kwargs.get(key, {}))
|
|
721
|
+
|
|
683
722
|
|
|
684
723
|
# It's important to set the default=None on these, except for list types where default
|
|
685
724
|
# is []. If the parsed Namespace has values set to None or [], we do not update. This
|
|
@@ -1040,6 +1079,26 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
1040
1079
|
util.warning(*msg)
|
|
1041
1080
|
|
|
1042
1081
|
|
|
1082
|
+
def update_tool_warn_err_counts_from_log_lines(
|
|
1083
|
+
self, log_lines: list, bad_strings: list, warning_strings: list
|
|
1084
|
+
) -> None:
|
|
1085
|
+
'''Given lines (list of str) from a log, update self.tool_[error|warning]_count values
|
|
1086
|
+
|
|
1087
|
+
Since Tool class is not always a parent in Command/CommandDesign/CommandSim, we
|
|
1088
|
+
have to modfiy these member names safely for pylint.
|
|
1089
|
+
|
|
1090
|
+
Derived classes may override this, especially if the Tool is known and reports
|
|
1091
|
+
the complete error/warning summary counts in a certain way.
|
|
1092
|
+
'''
|
|
1093
|
+
if not isinstance(self, Tool):
|
|
1094
|
+
return
|
|
1095
|
+
for line in log_lines:
|
|
1096
|
+
if any(bad_str in line for bad_str in bad_strings):
|
|
1097
|
+
setattr(self, 'tool_error_count', getattr(self, 'tool_error_count', 0) + 1)
|
|
1098
|
+
if any(warn_str in line for warn_str in warning_strings):
|
|
1099
|
+
setattr(self, 'tool_warning_count', getattr(self, 'tool_warning_count', 0) + 1)
|
|
1100
|
+
|
|
1101
|
+
|
|
1043
1102
|
class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
1044
1103
|
'''CommandDesign is the eda base class for command handlers that need to track files.
|
|
1045
1104
|
|
|
@@ -154,6 +154,8 @@ tools:
|
|
|
154
154
|
|
|
155
155
|
verilator:
|
|
156
156
|
defines: { }
|
|
157
|
+
log-warning-strings:
|
|
158
|
+
- "%Warning"
|
|
157
159
|
log-bad-strings:
|
|
158
160
|
- "%Error"
|
|
159
161
|
- "%Fatal"
|
|
@@ -239,8 +241,11 @@ tools:
|
|
|
239
241
|
defines:
|
|
240
242
|
OC_TOOL_RIVIERA: 1
|
|
241
243
|
RIVIERA: 1
|
|
244
|
+
log-warning-strings:
|
|
245
|
+
- "Warning: "
|
|
242
246
|
log-bad-strings:
|
|
243
|
-
- "Error:"
|
|
247
|
+
- "Error: "
|
|
248
|
+
- "Fatal: "
|
|
244
249
|
log-must-strings:
|
|
245
250
|
- "VSIM: Simulation has finished"
|
|
246
251
|
compile-args: |
|
|
@@ -261,8 +266,11 @@ tools:
|
|
|
261
266
|
defines:
|
|
262
267
|
OC_ASSERT_PROPERTY_NOT_SUPPORTED: 1
|
|
263
268
|
OC_TOOL_MODELSIM_ASE: 1
|
|
269
|
+
log-warning-strings:
|
|
270
|
+
- "Warning: "
|
|
264
271
|
log-bad-strings:
|
|
265
|
-
- "Error:"
|
|
272
|
+
- "Error: "
|
|
273
|
+
- "Fatal: "
|
|
266
274
|
log-must-strings:
|
|
267
275
|
- " vsim "
|
|
268
276
|
- "Errors: 0"
|
|
@@ -286,8 +294,11 @@ tools:
|
|
|
286
294
|
questa_fse:
|
|
287
295
|
defines:
|
|
288
296
|
OC_TOOL_QUESTA_FSE: 1
|
|
297
|
+
log-warning-strings:
|
|
298
|
+
- "Warning: "
|
|
289
299
|
log-bad-strings:
|
|
290
|
-
- "Error:"
|
|
300
|
+
- "Error: "
|
|
301
|
+
- "Fatal: "
|
|
291
302
|
log-must-strings:
|
|
292
303
|
- " vsim "
|
|
293
304
|
- "Errors: 0"
|
|
@@ -309,6 +320,9 @@ tools:
|
|
|
309
320
|
|
|
310
321
|
|
|
311
322
|
iverilog:
|
|
323
|
+
log-warning-strings:
|
|
324
|
+
- "Warning:"
|
|
325
|
+
- "WARNING:"
|
|
312
326
|
log-bad-strings:
|
|
313
327
|
- "Error:"
|
|
314
328
|
- "ERROR:"
|
|
@@ -328,6 +342,9 @@ tools:
|
|
|
328
342
|
cocotb:
|
|
329
343
|
defines:
|
|
330
344
|
OC_TOOL_COCOTB: null
|
|
345
|
+
log-warning-strings:
|
|
346
|
+
- "Warning:"
|
|
347
|
+
- "WARNING:"
|
|
331
348
|
log-bad-strings:
|
|
332
349
|
- "ERROR"
|
|
333
350
|
- "FAILED"
|
|
@@ -344,6 +361,14 @@ tools:
|
|
|
344
361
|
OC_TOOL_QUARTUS: null
|
|
345
362
|
|
|
346
363
|
vivado:
|
|
364
|
+
log-warning-strings:
|
|
365
|
+
- "WARNING: "
|
|
366
|
+
- "Warning: "
|
|
367
|
+
log-bad-strings:
|
|
368
|
+
- "FATAL: "
|
|
369
|
+
- "Fatal: "
|
|
370
|
+
- "ERROR: "
|
|
371
|
+
- "Error: "
|
|
347
372
|
sim-libraries:
|
|
348
373
|
- xil_defaultlib
|
|
349
374
|
- unisims_ver
|
|
@@ -7,13 +7,12 @@ import shutil
|
|
|
7
7
|
import sys
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
10
|
-
from opencos import
|
|
11
|
-
|
|
10
|
+
from opencos import eda_base
|
|
12
11
|
from opencos.tools.verilator import ToolVerilator
|
|
13
12
|
from opencos.tools.vivado import ToolVivado
|
|
14
13
|
from opencos.tools.cocotb import ToolCocotb
|
|
15
14
|
from opencos.tests import helpers
|
|
16
|
-
from opencos.tests.helpers import eda_wrap, eda_wrap_is_sim_fail, config, tools_loaded
|
|
15
|
+
from opencos.tests.helpers import Helpers, eda_wrap, eda_wrap_is_sim_fail, config, tools_loaded
|
|
17
16
|
from opencos.utils.markup_helpers import yaml_safe_load
|
|
18
17
|
from opencos.utils import status_constants
|
|
19
18
|
|
|
@@ -24,6 +23,10 @@ def chdir_remove_work_dir(relpath):
|
|
|
24
23
|
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
25
24
|
return helpers.chdir_remove_work_dir(THISPATH, relpath)
|
|
26
25
|
|
|
26
|
+
def filter_tools(tools: list) -> list:
|
|
27
|
+
'''Given a list of tool l, filters to return a list of tools that are loaded'''
|
|
28
|
+
return [x for x in tools if x in tools_loaded]
|
|
29
|
+
|
|
27
30
|
|
|
28
31
|
def test_tools_loaded():
|
|
29
32
|
'''Does not directly call 'eda.main' instead create a few Tool
|
|
@@ -107,40 +110,60 @@ list_of_added_sim_args = [
|
|
|
107
110
|
'--gui --test-mode',
|
|
108
111
|
]
|
|
109
112
|
|
|
113
|
+
list_of_loaded_tools = filter_tools(list_of_tools)
|
|
114
|
+
|
|
110
115
|
cannot_use_cocotb = 'cocotb' not in tools_loaded or \
|
|
111
116
|
('iverilog' not in tools_loaded and \
|
|
112
117
|
'verilator' not in tools_loaded)
|
|
113
118
|
CANNOT_USE_COCOTB_REASON = 'requires cocotb in tools_loaded, and one of (iverilog, verilator) too'
|
|
114
119
|
|
|
115
|
-
@pytest.mark.parametrize("command", list_of_commands)
|
|
116
|
-
@pytest.mark.parametrize("tool", list_of_tools)
|
|
117
|
-
@pytest.mark.parametrize("target,sim_expect_pass", list_of_deps_targets)
|
|
118
|
-
@pytest.mark.parametrize("added_sim_args_str", list_of_added_sim_args)
|
|
119
|
-
def test_sim_elab_tools_pass_or_fail(command, tool, target, sim_expect_pass, added_sim_args_str):
|
|
120
|
-
'''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-args> <parameter-target>
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
class TestSimElabTools(Helpers):
|
|
122
|
+
'''Tests for eda sim|elab for various tools with various args'''
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
124
|
+
DEFAULT_DIR = os.path.join(THISPATH, 'deps_files', 'test_err_fatal')
|
|
125
|
+
|
|
126
|
+
@pytest.mark.parametrize("command", list_of_commands)
|
|
127
|
+
@pytest.mark.parametrize("tool", list_of_loaded_tools)
|
|
128
|
+
@pytest.mark.parametrize("target,sim_expect_pass", list_of_deps_targets)
|
|
129
|
+
@pytest.mark.parametrize("added_sim_args_str", list_of_added_sim_args)
|
|
130
|
+
def test_pass_or_fail(
|
|
131
|
+
self, command, tool, target, sim_expect_pass, added_sim_args_str
|
|
132
|
+
):
|
|
133
|
+
'''tests that: eda <sim|elab> --tool <parameter-tool> <parameter-args> <parameter-target>
|
|
134
|
+
|
|
135
|
+
will correctly pass or fail depending on if it is supported or not.
|
|
136
|
+
|
|
137
|
+
Also tests for: non-gui, or --gui --test-mode (runs non-gui, but most python args will
|
|
138
|
+
be for --gui mode, signal logging, etc).
|
|
139
|
+
'''
|
|
140
|
+
added_args_str = ''
|
|
141
|
+
if command == 'sim':
|
|
142
|
+
added_args_str = added_sim_args_str
|
|
143
|
+
|
|
144
|
+
rc = self.log_it(f'{command} --tool {tool} {added_args_str} {target}')
|
|
145
|
+
print(f'{rc=}')
|
|
146
|
+
tool_error_count_lines = self.get_log_lines_with('tool errors')
|
|
147
|
+
if command != 'sim' or sim_expect_pass:
|
|
148
|
+
# command='elab' should pass.
|
|
149
|
+
assert rc == 0
|
|
150
|
+
assert tool_error_count_lines
|
|
151
|
+
assert all('tool warnings' in line for line in tool_error_count_lines)
|
|
152
|
+
assert all(' 0 tool errors' in line for line in tool_error_count_lines)
|
|
153
|
+
|
|
154
|
+
else:
|
|
155
|
+
assert eda_wrap_is_sim_fail(rc)
|
|
156
|
+
assert tool_error_count_lines
|
|
157
|
+
assert all('tool warnings' in line for line in tool_error_count_lines)
|
|
158
|
+
# May or may not have reported tool errors.
|
|
159
|
+
assert all('tool errors' in line for line in tool_error_count_lines)
|
|
160
|
+
# The final line of tool warnings/errors should have > 0 tool errors,
|
|
161
|
+
# since we were checking SV $error and $fatal
|
|
162
|
+
assert ' 0 tool errors' not in tool_error_count_lines[-1]
|
|
163
|
+
# The line should end with ' X tool errors'
|
|
164
|
+
parts = tool_error_count_lines[-1].split()
|
|
165
|
+
assert parts[-3].isdigit()
|
|
166
|
+
assert int(parts[-3]) in (1, 2, 3) # we should have at least 1, but some tools dup.
|
|
144
167
|
|
|
145
168
|
|
|
146
169
|
@pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
|
|
@@ -93,7 +93,7 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
|
|
|
93
93
|
def compile(self):
|
|
94
94
|
if self.args['stop-before-compile']:
|
|
95
95
|
return
|
|
96
|
-
self.run_commands_check_logs(self.iverilog_command_lists
|
|
96
|
+
self.run_commands_check_logs(self.iverilog_command_lists)
|
|
97
97
|
|
|
98
98
|
def elaborate(self):
|
|
99
99
|
pass
|
|
@@ -148,7 +148,7 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
|
|
|
148
148
|
|
|
149
149
|
command_list += list(self.files_sv) + list(self.files_v)
|
|
150
150
|
|
|
151
|
-
return [ util.ShellCommandList(command_list) ]
|
|
151
|
+
return [ util.ShellCommandList(command_list, tee_fpath='compile.log') ]
|
|
152
152
|
|
|
153
153
|
def get_elaborate_command_lists(self, **kwargs) -> list:
|
|
154
154
|
return []
|
|
@@ -21,6 +21,7 @@ class ToolRiviera(ToolModelsimAse):
|
|
|
21
21
|
_TOOL = 'riviera'
|
|
22
22
|
_EXE = 'vsim'
|
|
23
23
|
use_vopt = False
|
|
24
|
+
uvm_versions = set()
|
|
24
25
|
|
|
25
26
|
def get_versions(self) -> str:
|
|
26
27
|
if self._VERSION:
|
|
@@ -40,7 +41,17 @@ class ToolRiviera(ToolModelsimAse):
|
|
|
40
41
|
)
|
|
41
42
|
stdout = version_ret.stdout.decode('utf-8', errors='replace').rstrip()
|
|
42
43
|
|
|
43
|
-
#
|
|
44
|
+
# Get the UVM versions in the install directory. Note this may run
|
|
45
|
+
# more than once, so only do this if self.uvm_versions not yet set:
|
|
46
|
+
riviera_path, _ = os.path.split(self.sim_exe_base_path)
|
|
47
|
+
vlib_path = os.path.join(riviera_path, 'vlib')
|
|
48
|
+
if not self.uvm_versions and os.path.isdir(vlib_path):
|
|
49
|
+
for item in os.listdir(vlib_path):
|
|
50
|
+
# uvm-1.1, uvm-1.1d - so don't pick anything > 9 chars (uvm-M.mRr)
|
|
51
|
+
if item.startswith('uvm-') and '1800' not in item and len(item) <= 9:
|
|
52
|
+
self.uvm_versions.add(item[4:])
|
|
53
|
+
|
|
54
|
+
# For Version, expect:
|
|
44
55
|
# Aldec, Inc. Riviera-PRO version 2025.04.139.9738 built for Linux64 on May 30, 2025
|
|
45
56
|
left, right = stdout.split('version')
|
|
46
57
|
if 'Riviera' not in left:
|
|
@@ -76,6 +87,18 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
76
87
|
'bring your own .tcl file to run in Riviera (vsim) for coverage. The default'
|
|
77
88
|
' tcl steps are (from tool config in --config-yml): '
|
|
78
89
|
) + '; '.join(self.tool_config.get('simulate-coverage-tcl', [])),
|
|
90
|
+
'uvm': (
|
|
91
|
+
'Attempts to support UVM. Adds to vlog: -l uvm +incdir+PATH for the PATH to'
|
|
92
|
+
' uvm_macros.svh for the installed version of Riviera used.'
|
|
93
|
+
),
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
if self.uvm_versions:
|
|
97
|
+
# set default to latest version:
|
|
98
|
+
self.args['uvm-version'] = sorted(self.uvm_versions)[-1]
|
|
99
|
+
|
|
100
|
+
self.args_kwargs.update({
|
|
101
|
+
'uvm-version': { 'choices': list(self.uvm_versions) }
|
|
79
102
|
})
|
|
80
103
|
|
|
81
104
|
def set_tool_defines(self):
|
|
@@ -136,7 +159,9 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
136
159
|
return []
|
|
137
160
|
|
|
138
161
|
|
|
139
|
-
def write_vlog_dot_f(
|
|
162
|
+
def write_vlog_dot_f( # pylint: disable=too-many-branches
|
|
163
|
+
self, filename: str = 'vlog.f'
|
|
164
|
+
) -> None:
|
|
140
165
|
'''Returns none, creates filename (str) for a vlog.f'''
|
|
141
166
|
vlog_dot_f_lines = []
|
|
142
167
|
|
|
@@ -153,6 +178,12 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
153
178
|
vlog_dot_f_fname = filename
|
|
154
179
|
vlog_dot_f_fpath = os.path.join(self.args['work-dir'], vlog_dot_f_fname)
|
|
155
180
|
|
|
181
|
+
if self.args['uvm']:
|
|
182
|
+
vlog_dot_f_lines.extend([
|
|
183
|
+
f'-uvmver {self.args["uvm-version"]}',
|
|
184
|
+
'-dbg'
|
|
185
|
+
])
|
|
186
|
+
|
|
156
187
|
for value in self.incdirs:
|
|
157
188
|
vlog_dot_f_lines += [ f"+incdir+{value}" ]
|
|
158
189
|
|
|
@@ -176,6 +176,30 @@ class CommandElabSlang(CommandElab, ToolSlang):
|
|
|
176
176
|
def get_post_simulate_command_lists(self, **kwargs) -> list:
|
|
177
177
|
return []
|
|
178
178
|
|
|
179
|
+
def update_tool_warn_err_counts_from_log_lines(
|
|
180
|
+
self, log_lines: list, bad_strings: list, warning_strings: list
|
|
181
|
+
) -> None:
|
|
182
|
+
'''
|
|
183
|
+
Overriden from Command, we ignore bad_strings/warning_strings and use a custom
|
|
184
|
+
checker.
|
|
185
|
+
'''
|
|
186
|
+
for line in log_lines:
|
|
187
|
+
if not line.startswith('Build failed: '):
|
|
188
|
+
continue
|
|
189
|
+
if not all(x in line for x in ('errors', 'warnings')):
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
parts = line.strip().split()
|
|
193
|
+
if len(parts) < 6:
|
|
194
|
+
continue
|
|
195
|
+
|
|
196
|
+
errs = parts[2]
|
|
197
|
+
warns = parts[4]
|
|
198
|
+
if errs.isdigit():
|
|
199
|
+
self.tool_error_count += int(errs)
|
|
200
|
+
if warns.isdigit():
|
|
201
|
+
self.tool_warning_count += int(warns)
|
|
202
|
+
|
|
179
203
|
def _get_slang_command_list_start(self) -> list:
|
|
180
204
|
command_list = [self.slang_exe]
|
|
181
205
|
|
|
@@ -147,6 +147,28 @@ class CommandElabSurelog(CommandElab, ToolSurelog):
|
|
|
147
147
|
command_lists=self.surelog_command_lists, line_breaks=True
|
|
148
148
|
)
|
|
149
149
|
|
|
150
|
+
def update_tool_warn_err_counts_from_log_lines(
|
|
151
|
+
self, log_lines: list, bad_strings: list, warning_strings: list
|
|
152
|
+
) -> None:
|
|
153
|
+
'''
|
|
154
|
+
Overriden from Command, we ignore bad_strings/warning_strings and use a custom
|
|
155
|
+
checker.
|
|
156
|
+
'''
|
|
157
|
+
for line in log_lines:
|
|
158
|
+
line = line.strip()
|
|
159
|
+
if line.endswith(' 0'):
|
|
160
|
+
continue
|
|
161
|
+
if line.startswith('[ FATAL] : ') or \
|
|
162
|
+
line.startswith('[ SYNTAX] : ') or \
|
|
163
|
+
line.startswith('[ ERROR] : '):
|
|
164
|
+
parts = line.split()
|
|
165
|
+
if parts[-1].isdigit():
|
|
166
|
+
self.tool_error_count += int(parts[-1])
|
|
167
|
+
if line.startswith('[WARNING] : '):
|
|
168
|
+
parts = line.split()
|
|
169
|
+
if parts[-1].isdigit():
|
|
170
|
+
self.tool_warning_count += int(parts[-1])
|
|
171
|
+
|
|
150
172
|
|
|
151
173
|
class CommandLintSurelog(CommandElabSurelog):
|
|
152
174
|
'''CommandLintSurelog is a command handler for: eda lint --tool=surelog.'''
|
|
@@ -82,7 +82,6 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
82
82
|
'lint-only': False,
|
|
83
83
|
'cc-mode': False,
|
|
84
84
|
'verilator-coverage-args': [],
|
|
85
|
-
'uvm': False,
|
|
86
85
|
'x-assign': '',
|
|
87
86
|
'x-initial': '',
|
|
88
87
|
})
|
|
@@ -117,9 +116,9 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
117
116
|
' Also conditinally adds to verilated exe call:'
|
|
118
117
|
' +verilator+rand+reset+[0,2] for arg values 0, unique|fast'),
|
|
119
118
|
'uvm': (
|
|
120
|
-
'Warns on Verilator < 5.042, or missing $UVM_HOME environment
|
|
121
|
-
' .env, $UVM_HOME/uvm_pkg.sv should exist), and will run verilator
|
|
122
|
-
' -Wno-fatal +define+UVM_NO_DPI'
|
|
119
|
+
'Enables UVM. Warns on Verilator < 5.042, or missing $UVM_HOME environment'
|
|
120
|
+
' var set (or in .env, $UVM_HOME/uvm_pkg.sv should exist), and will run verilator'
|
|
121
|
+
' with args: -Wno-fatal +define+UVM_NO_DPI'
|
|
123
122
|
),
|
|
124
123
|
'verilator-coverage-args': (
|
|
125
124
|
'Requires --coverage, args to be applied to verilator_coverage, which runs'
|
|
@@ -127,6 +126,12 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
127
126
|
),
|
|
128
127
|
})
|
|
129
128
|
|
|
129
|
+
|
|
130
|
+
self.args_kwargs.update({
|
|
131
|
+
'x-assign': { 'choices': ['0', '1', 'unique', 'fast'] },
|
|
132
|
+
'x-initial': { 'choices': ['0', 'unique', 'fast'] },
|
|
133
|
+
})
|
|
134
|
+
|
|
130
135
|
self.verilate_command_lists = []
|
|
131
136
|
self.lint_only_command_lists = []
|
|
132
137
|
self.verilated_exec_command_lists = []
|
|
@@ -562,7 +567,8 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
562
567
|
'version > v5.042')
|
|
563
568
|
|
|
564
569
|
if not os.environ.get('UVM_HOME', ''):
|
|
565
|
-
util.warning('--uvm set, however env (or .env or --env-file)
|
|
570
|
+
util.warning('--uvm set, however env (or .env or --env-file)',
|
|
571
|
+
'$UVM_HOME is not set')
|
|
566
572
|
|
|
567
573
|
uvm_pkg_found = self._verilator_support_uvm_pkg_fpath(add_if_found=add_uvm_pkg_if_found)
|
|
568
574
|
if warnings and not uvm_pkg_found:
|
|
@@ -225,6 +225,8 @@ class CommandSimVivado(CommandSim, ToolVivado):
|
|
|
225
225
|
|
|
226
226
|
if self.tool_config.get('elab-waves-args', ''):
|
|
227
227
|
command_list += self.tool_config.get('elab-waves-args', '').split()
|
|
228
|
+
if self.args['uvm']:
|
|
229
|
+
command_list.extend(['-L', 'uvm'])
|
|
228
230
|
elif self.args['gui'] and self.args['waves']:
|
|
229
231
|
command_list += ['-debug', 'all']
|
|
230
232
|
elif self.args['gui']:
|
|
@@ -305,6 +307,8 @@ class CommandSimVivado(CommandSim, ToolVivado):
|
|
|
305
307
|
command_list[0] += ".bat"
|
|
306
308
|
if typ == 'sv':
|
|
307
309
|
command_list.append('-sv')
|
|
310
|
+
if self.args['uvm']:
|
|
311
|
+
command_list.extend(['-L', 'uvm'])
|
|
308
312
|
command_list += self.tool_config.get('compile-args', '').split()
|
|
309
313
|
if util.args['verbose']:
|
|
310
314
|
command_list += ['-v', '2']
|
|
@@ -901,7 +901,8 @@ def exit( # pylint: disable=redefined-builtin
|
|
|
901
901
|
elif args['warnings']:
|
|
902
902
|
info_color = Colors.yellow
|
|
903
903
|
info(
|
|
904
|
-
f"{start}Exiting with {args['warnings']} warnings
|
|
904
|
+
f"{start}Exiting with {Colors.bold}{args['warnings']} warnings{info_color},",
|
|
905
|
+
f"{Colors.bold}{args['errors']} errors",
|
|
905
906
|
color=info_color
|
|
906
907
|
)
|
|
907
908
|
sys.exit(error_code)
|
|
@@ -132,11 +132,11 @@ def get_terminal_columns():
|
|
|
132
132
|
|
|
133
133
|
Returns:
|
|
134
134
|
int: The number of columns in the terminal, or a default value (e.g., 80)
|
|
135
|
-
if the terminal size cannot be determined.
|
|
135
|
+
if the terminal size cannot be determined. Min value of 40 is returned.
|
|
136
136
|
"""
|
|
137
137
|
try:
|
|
138
138
|
size = os.get_terminal_size()
|
|
139
|
-
return size.columns
|
|
139
|
+
return max(40, size.columns)
|
|
140
140
|
except OSError:
|
|
141
141
|
# Handle cases where the terminal size cannot be determined (e.g., not in a TTY)
|
|
142
142
|
return 80 # Default to 80 columns
|
|
@@ -166,13 +166,13 @@ def pretty_list_columns_manual(data: list, num_columns: int = 4, auto_columns: b
|
|
|
166
166
|
max_line_len = 0
|
|
167
167
|
for x in max_lengths:
|
|
168
168
|
max_line_len += x + _spacing
|
|
169
|
-
if max_line_len
|
|
169
|
+
if max_line_len >= window_cols:
|
|
170
170
|
# subtract a column (already >= 2):
|
|
171
171
|
ret_lines.extend(
|
|
172
172
|
pretty_list_columns_manual(data=data, num_columns=num_columns-1, auto_columns=True)
|
|
173
173
|
)
|
|
174
174
|
return ret_lines
|
|
175
|
-
if max_line_len + max_item_len + _spacing
|
|
175
|
+
if max_line_len + max_item_len + _spacing < window_cols:
|
|
176
176
|
# add 1 more column if we're guaranteed to have room.
|
|
177
177
|
ret_lines.extend(
|
|
178
178
|
pretty_list_columns_manual(data=data, num_columns=num_columns+1, auto_columns=True)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: A simple Python package for wrapping RTL simuliatons and synthesis
|
|
5
5
|
Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/cognichip/opencos
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|