opencos-eda 0.3.7__py3-none-any.whl → 0.3.9__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/sim.py +61 -11
- opencos/eda.py +62 -8
- opencos/eda_base.py +77 -18
- opencos/eda_config.py +1 -0
- opencos/eda_config_defaults.yml +42 -8
- opencos/tests/test_tools.py +53 -30
- opencos/tools/iverilog.py +2 -2
- opencos/tools/modelsim_ase.py +19 -378
- opencos/tools/questa.py +42 -247
- opencos/tools/questa_common.py +481 -0
- opencos/tools/questa_fe.py +84 -0
- opencos/tools/questa_fse.py +7 -8
- opencos/tools/riviera.py +60 -12
- opencos/tools/slang.py +24 -0
- opencos/tools/surelog.py +22 -0
- opencos/tools/verilator.py +11 -5
- opencos/tools/vivado.py +4 -0
- opencos/util.py +2 -1
- opencos/utils/str_helpers.py +4 -4
- opencos/utils/vsim_helper.py +8 -1
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/METADATA +2 -1
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/RECORD +27 -25
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/WHEEL +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.3.7.dist-info → opencos_eda-0.3.9.dist-info}/top_level.txt +0 -0
opencos/commands/sim.py
CHANGED
|
@@ -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):
|
opencos/eda.py
CHANGED
|
@@ -410,7 +410,8 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
|
|
|
410
410
|
|
|
411
411
|
deferred_tokens = unparsed
|
|
412
412
|
if not command:
|
|
413
|
-
util.error("
|
|
413
|
+
util.error("'eda' didn't get a command, or command is invalid (run with --help to see",
|
|
414
|
+
"valid commands)!")
|
|
414
415
|
return 2
|
|
415
416
|
|
|
416
417
|
sco = config['command_handler'][command](config=config) # sub command object
|
|
@@ -430,7 +431,12 @@ def process_tokens( # pylint: disable=too-many-branches,too-many-statements,too-
|
|
|
430
431
|
command not in config.get('command_determines_tool', []) and \
|
|
431
432
|
command not in config.get('command_tool_is_optional', []):
|
|
432
433
|
use_tool = which_tool(command, config)
|
|
433
|
-
|
|
434
|
+
if use_tool:
|
|
435
|
+
util.info(f"--tool not specified, using default for {command=}: {use_tool}")
|
|
436
|
+
else:
|
|
437
|
+
# Not all commands have a hard requirement on tool (such as 'multi') because we
|
|
438
|
+
# haven't examined sub-commands yet.
|
|
439
|
+
util.info(f'--tool not specified, will attempt to determine tool(s) for {command=}.')
|
|
434
440
|
setattr(sco, 'auto_tool_applied', True)
|
|
435
441
|
|
|
436
442
|
rc = check_command_handler_cls(command_obj=sco, command=command, parsed_args=parsed)
|
|
@@ -483,12 +489,60 @@ def check_command_handler_cls(command_obj:object, command:str, parsed_args) -> i
|
|
|
483
489
|
if not isinstance(sco, cls):
|
|
484
490
|
# If someone set --tool verilator for command=synth, then our 'sco' will have defaulted
|
|
485
491
|
# to CommandSynth with no tool attached. If we don't have a tool set, error and return.
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
parsed_tool
|
|
490
|
-
|
|
491
|
-
|
|
492
|
+
parsed_tool = getattr(parsed_args, 'tool', '')
|
|
493
|
+
auto_tool_entry = command_obj.config.get(
|
|
494
|
+
'auto_tools_order', [{}])[0].get(parsed_tool, {})
|
|
495
|
+
if parsed_tool and not auto_tool_entry:
|
|
496
|
+
util.warning(
|
|
497
|
+
f"{command=} for tool '{parsed_tool}' is using handling class '{type(sco)}',",
|
|
498
|
+
f"but missing requirement {cls}, likely because the tool was not loaded",
|
|
499
|
+
"(not in PATH) or mis-configured (such as missing a Tool based class)"
|
|
500
|
+
)
|
|
501
|
+
return util.error(
|
|
502
|
+
f"EDA {command=} for tool '{parsed_tool}' cannot be run because tool",
|
|
503
|
+
f"'{parsed_tool}' is not known to `eda`. It does not exist in the config:",
|
|
504
|
+
"see informational message for --config-yml, and check that file's",
|
|
505
|
+
"auto_tools_order."
|
|
506
|
+
)
|
|
507
|
+
if parsed_tool:
|
|
508
|
+
util.warning(
|
|
509
|
+
f"{command=} for tool '{parsed_tool}' is using handling class '{type(sco)}',",
|
|
510
|
+
f"but missing requirement {cls}, likely because the tool was not loaded",
|
|
511
|
+
"(not in PATH) or mis-configured (such as missing a Tool based class)"
|
|
512
|
+
)
|
|
513
|
+
for k,v in auto_tool_entry.items():
|
|
514
|
+
if k == 'exe' or k.startswith('requires_cmd'):
|
|
515
|
+
util.warning(
|
|
516
|
+
f"tool '{parsed_tool}' has requirements that may not have been met --",
|
|
517
|
+
f"{k}: {v}"
|
|
518
|
+
)
|
|
519
|
+
if k == 'requires_vsim_helper':
|
|
520
|
+
if found_tool := vsim_helper.found():
|
|
521
|
+
util.warning(
|
|
522
|
+
f"tool '{parsed_tool}' was not found, vsim appears to be for tool",
|
|
523
|
+
f"'{found_tool}'"
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
return util.error(
|
|
527
|
+
f"EDA {command=} for tool '{parsed_tool}' is not supported (tool",
|
|
528
|
+
f"'{parsed_tool}' cannot run {command=}). It is likely that tool",
|
|
529
|
+
f"'{parsed_tool}' is not in PATH, or was unable to be loaded due to missing",
|
|
530
|
+
"requirements, or missing information when checking the exe version."
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
# No parsed_tool.
|
|
534
|
+
util.warning(
|
|
535
|
+
f"{command=} for default tool (--tool not set) is using handling class",
|
|
536
|
+
f"'{type(sco)}', but missing requirement {cls}, likely because the tool was not",
|
|
537
|
+
"loaded (not in PATH) or mis-configured (such as missing a Tool based class)"
|
|
538
|
+
)
|
|
539
|
+
return util.error(
|
|
540
|
+
f"EDA {command=} for default tool (--tool not set) is not supported (default",
|
|
541
|
+
f"tool cannot run {command=}). It appears that no suitable default tool to run",
|
|
542
|
+
f"{command=} was automatically found, was not in PATH, or was unable to be loaded",
|
|
543
|
+
"due to missing requirements, or missing information when checking the exe version."
|
|
544
|
+
)
|
|
545
|
+
|
|
492
546
|
return 0
|
|
493
547
|
|
|
494
548
|
|
opencos/eda_base.py
CHANGED
|
@@ -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
|
|
opencos/eda_config.py
CHANGED
opencos/eda_config_defaults.yml
CHANGED
|
@@ -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
|
|
@@ -485,7 +510,7 @@ auto_tools_order:
|
|
|
485
510
|
lec: opencos.tools.slang_yosys.CommandLecYosys
|
|
486
511
|
|
|
487
512
|
questa:
|
|
488
|
-
exe:
|
|
513
|
+
exe: vsim
|
|
489
514
|
requires_vsim_helper: True
|
|
490
515
|
handlers:
|
|
491
516
|
lint: opencos.tools.questa.CommandLintQuesta
|
|
@@ -503,13 +528,14 @@ auto_tools_order:
|
|
|
503
528
|
elab: opencos.tools.riviera.CommandElabRiviera
|
|
504
529
|
sim: opencos.tools.riviera.CommandSimRiviera
|
|
505
530
|
|
|
506
|
-
|
|
531
|
+
questa_fe:
|
|
507
532
|
exe: vsim
|
|
508
533
|
requires_vsim_helper: True
|
|
509
534
|
handlers:
|
|
510
|
-
lint: opencos.tools.
|
|
511
|
-
elab: opencos.tools.
|
|
512
|
-
sim:
|
|
535
|
+
lint: opencos.tools.questa_fe.CommandLintQuestaFe
|
|
536
|
+
elab: opencos.tools.questa_fe.CommandElabQuestaFe
|
|
537
|
+
sim: opencos.tools.questa_fe.CommandSimQuestaFe
|
|
538
|
+
flist: opencos.tools.questa_fe.CommandFListQuestaFe
|
|
513
539
|
|
|
514
540
|
questa_fse: # free student edition, works similar to modelsim_ase
|
|
515
541
|
exe: vsim
|
|
@@ -520,6 +546,14 @@ auto_tools_order:
|
|
|
520
546
|
sim: opencos.tools.questa_fse.CommandSimQuestaFse
|
|
521
547
|
flist: opencos.tools.questa_fse.CommandFListQuestaFse
|
|
522
548
|
|
|
549
|
+
modelsim_ase:
|
|
550
|
+
exe: vsim
|
|
551
|
+
requires_vsim_helper: True
|
|
552
|
+
handlers:
|
|
553
|
+
lint: opencos.tools.modelsim_ase.CommandLintModelsimAse
|
|
554
|
+
elab: opencos.tools.modelsim_ase.CommandElabModelsimAse
|
|
555
|
+
sim: opencos.tools.modelsim_ase.CommandSimModelsimAse
|
|
556
|
+
|
|
523
557
|
iverilog:
|
|
524
558
|
exe: iverilog
|
|
525
559
|
handlers:
|