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 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 ['log-bad-strings', 'log-must-strings']:
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, _ = self.exec(
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, filename: str = '', file_contents_str: str = '',
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("Didn't get a command!")
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
- util.info(f"--tool not specified, using default for {command=}: {use_tool}")
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
- util.warning(f"{command=} is using handling class '{type(sco)}' (but missing",
487
- f"requirement {cls}, likely because we aren't using a derived class",
488
- "for a specific tool)")
489
- parsed_tool = getattr(parsed_args, 'tool', '??')
490
- return util.error(f"EDA {command=} for tool '{parsed_tool}' is not",
491
- f"supported (this tool '{parsed_tool}' cannot run {command=})")
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
- if report and self.status > 0:
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 self.status > 0
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 = ' - '.join(
387
- x for x in (self.command_name, self.args.get('tool', ''),
388
- self.args.get('top', '')) if x
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
- if return_code == 255:
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.debug(f"{safe_emoji('❌ ')}exec: returned with error (return code:",
569
- f"{return_code})")
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
@@ -57,6 +57,7 @@ class Defaults:
57
57
  'defines',
58
58
  'log-bad-strings',
59
59
  'log-must-strings',
60
+ 'log-warning-strings',
60
61
  'sim-libraries',
61
62
  'compile-args',
62
63
  'compile-waves-args',
@@ -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: qrun
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
- modelsim_ase:
531
+ questa_fe:
507
532
  exe: vsim
508
533
  requires_vsim_helper: True
509
534
  handlers:
510
- lint: opencos.tools.modelsim_ase.CommandLintModelsimAse
511
- elab: opencos.tools.modelsim_ase.CommandElabModelsimAse
512
- sim: opencos.tools.modelsim_ase.CommandSimModelsimAse
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: