opencos-eda 0.3.8__py3-none-any.whl → 0.3.10__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.
Files changed (42) hide show
  1. opencos/commands/deps_help.py +40 -21
  2. opencos/commands/sim.py +0 -1
  3. opencos/deps/deps_file.py +82 -79
  4. opencos/eda.py +108 -17
  5. opencos/eda_base.py +8 -4
  6. opencos/eda_config.py +8 -1
  7. opencos/eda_config_defaults.yml +14 -5
  8. opencos/eda_deps_bash_completion.bash +37 -15
  9. opencos/tools/modelsim_ase.py +19 -378
  10. opencos/tools/questa.py +42 -247
  11. opencos/tools/questa_common.py +480 -0
  12. opencos/tools/questa_fe.py +84 -0
  13. opencos/tools/questa_fse.py +7 -8
  14. opencos/tools/riviera.py +27 -10
  15. opencos/tools/verilator.py +1 -0
  16. opencos/utils/str_helpers.py +7 -0
  17. opencos/utils/vsim_helper.py +53 -21
  18. {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/METADATA +2 -1
  19. {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/RECORD +24 -40
  20. {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/entry_points.txt +1 -0
  21. opencos/tests/__init__.py +0 -0
  22. opencos/tests/custom_config.yml +0 -13
  23. opencos/tests/deps_files/command_order/DEPS.yml +0 -44
  24. opencos/tests/deps_files/error_msgs/DEPS.yml +0 -55
  25. opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -4
  26. opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
  27. opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -50
  28. opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -54
  29. opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -4
  30. opencos/tests/helpers.py +0 -354
  31. opencos/tests/test_build.py +0 -12
  32. opencos/tests/test_deps_helpers.py +0 -207
  33. opencos/tests/test_deps_schema.py +0 -30
  34. opencos/tests/test_eda.py +0 -921
  35. opencos/tests/test_eda_elab.py +0 -110
  36. opencos/tests/test_eda_synth.py +0 -150
  37. opencos/tests/test_oc_cli.py +0 -25
  38. opencos/tests/test_tools.py +0 -404
  39. {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/WHEEL +0 -0
  40. {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/licenses/LICENSE +0 -0
  41. {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/licenses/LICENSE.spdx +0 -0
  42. {opencos_eda-0.3.8.dist-info → opencos_eda-0.3.10.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,480 @@
1
+ ''' opencos.tools.questa - Used by opencos.eda for sim/elab commands w/ --tool=questa.
2
+
3
+ Contains classes for ToolQuesta, and CommonSimQuesta.
4
+
5
+ '''
6
+
7
+ # pylint: disable=R0801 # (setting similar, but not identical, self.defines key/value pairs)
8
+
9
+ # TODO(drew): fix these pylint eventually:
10
+ # pylint: disable=too-many-branches
11
+
12
+ import os
13
+ import re
14
+ import shutil
15
+
16
+ from opencos import util
17
+ from opencos.commands import sim, CommandSim, CommandFList
18
+ from opencos.eda_base import Tool
19
+ from opencos.utils.str_helpers import sanitize_defines_for_sh
20
+
21
+ class ToolQuesta(Tool):
22
+ '''Base class for CommandSimQuesta, collects version information about qrun'''
23
+
24
+ _TOOL = 'questa'
25
+ _EXE = 'vsim'
26
+
27
+ starter_edition = False
28
+ use_vopt = False # set manually or by get_versions() (after __init__ has set self._EXE)
29
+ sim_exe = '' # vsim or qrun
30
+ sim_exe_base_path = ''
31
+ questa_major = None
32
+ questa_minor = None
33
+
34
+ def __init__(self, config: dict):
35
+ super().__init__(config=config)
36
+
37
+ def get_versions(self) -> str:
38
+ if self._VERSION:
39
+ return self._VERSION
40
+ path = shutil.which(self._EXE)
41
+ if not path:
42
+ self.error(f"{self._EXE} not in path, need to setup",
43
+ "(i.e. source /opt/intelFPGA_pro/23.4/settings64.sh")
44
+ util.debug(f"{path=}")
45
+ if self._EXE.endswith('qrun') and \
46
+ any(x in path for x in ('modelsim_ase', 'questa_fse')):
47
+ util.warning(f"{self._EXE=} Questa path is for starter edition",
48
+ "(modelsim_ase, questa_fse), consider using --tool=modelsim_ase",
49
+ "or --tool=questa_fse, or similar")
50
+ else:
51
+ self.sim_exe = path
52
+ self.sim_exe_base_path, _ = os.path.split(path)
53
+
54
+ m = re.search(r'(\d+)\.(\d+)', path)
55
+ if m:
56
+ self.questa_major = int(m.group(1))
57
+ self.questa_minor = int(m.group(2))
58
+ self._VERSION = str(self.questa_major) + '.' + str(self.questa_minor)
59
+ else:
60
+ self.error("Questa path doesn't specificy version, expecting (d+.d+)")
61
+ return self._VERSION
62
+
63
+ def set_tool_defines(self):
64
+ # Will only be called from an object which also inherits from CommandDesign,
65
+ # i.e. has self.defines
66
+ self.defines['OC_TOOL_QUESTA'] = None
67
+ self.defines[f'OC_TOOL_QUESTA_{self.questa_major:d}_{self.questa_minor:d}'] = None
68
+
69
+
70
+
71
+ class CommonSimQuesta(CommandSim, ToolQuesta):
72
+ '''CommonSimQuesta is a the base command handler for:
73
+
74
+ eda sim --tool=[modelsim_ase|questa|questa_fse]
75
+ '''
76
+
77
+ def __init__(self, config: dict):
78
+ CommandSim.__init__(self, config=config)
79
+ ToolQuesta.__init__(self, config=self.config)
80
+ self.shell_command = os.path.join(self.sim_exe_base_path, 'vsim')
81
+ self.starter_edition = True
82
+ self.args.update({
83
+ 'tool': self._TOOL, # override
84
+ 'gui': False,
85
+ 'vopt': self.use_vopt,
86
+ })
87
+ self.args_help.update({
88
+ 'vopt': (
89
+ 'Boolean to enable/disable use of vopt step prior to vsim step'
90
+ ' Note that vopt args can be controlled with --elab-args=<value1>'
91
+ ' --elab-args=<value2> ...'
92
+ )
93
+ })
94
+
95
+
96
+ def run_in_batch_mode(self) -> bool:
97
+ '''Returns bool if we should run in batch mode (-c) from command line'''
98
+ if self.args['test-mode']:
99
+ return True
100
+ if self.args['gui']:
101
+ return False
102
+ return True
103
+
104
+
105
+ def prepare_compile(self):
106
+ self.set_tool_defines()
107
+ self.write_vlog_dot_f()
108
+ self.write_vsim_dot_do(dot_do_to_write='all')
109
+
110
+ vsim_command_lists = self.get_compile_command_lists()
111
+ util.write_shell_command_file(
112
+ dirpath=self.args['work-dir'],
113
+ filename='compile_only.sh',
114
+ command_lists=vsim_command_lists
115
+ )
116
+
117
+ vsim_command_lists = self.get_elaborate_command_lists()
118
+ util.write_shell_command_file(
119
+ dirpath=self.args['work-dir'],
120
+ filename='compile_elaborate_only.sh',
121
+ command_lists=vsim_command_lists
122
+ )
123
+
124
+ # Write simulate.sh and all.sh to work-dir:
125
+ vsim_command_lists = self.get_simulate_command_lists()
126
+ self.write_sh_scripts_to_work_dir(
127
+ compile_lists=[], elaborate_lists=[], simulate_lists=vsim_command_lists
128
+ )
129
+
130
+ def compile(self):
131
+ if self.args['stop-before-compile']:
132
+ # don't run anything, save everyting we've already run in _prep_compile()
133
+ return
134
+ if self.args['stop-after-compile']:
135
+ vsim_command_lists = self.get_compile_command_lists()
136
+ self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log',
137
+ must_strings=['Errors: 0'], use_must_strings=False)
138
+
139
+ def elaborate(self):
140
+ if self.args['stop-before-compile']:
141
+ return
142
+ if self.args['stop-after-compile']:
143
+ return
144
+ if self.args['stop-after-elaborate']:
145
+ # only run this if we stop after elaborate (simulate run it all)
146
+ vsim_command_lists = self.get_elaborate_command_lists()
147
+ self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log')
148
+
149
+ def simulate(self):
150
+ if self.args['stop-before-compile'] or self.args['stop-after-compile'] or \
151
+ self.args['stop-after-elaborate']:
152
+ # don't run this if we're stopping before/after compile/elab
153
+ return
154
+ vsim_command_lists = self.get_simulate_command_lists()
155
+ self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log')
156
+
157
+ def get_compile_command_lists(self, **kwargs) -> list:
158
+ # This will also set up a compile.
159
+ vsim_command_list = [
160
+ self.sim_exe,
161
+ '-c' if self.run_in_batch_mode() else '',
162
+ '-do', 'vsim_vlogonly.do', '-logfile', 'sim.log',
163
+ ]
164
+ return [vsim_command_list]
165
+
166
+ def get_elaborate_command_lists(self, **kwargs) -> list:
167
+ # This will also set up a compile, for vlog + vsim (0 time)
168
+ vsim_command_list = [
169
+ self.sim_exe,
170
+ '-c' if self.run_in_batch_mode() else '',
171
+ '-do', 'vsim_lintonly.do', '-logfile', 'sim.log',
172
+ ]
173
+ return [vsim_command_list]
174
+
175
+ def get_simulate_command_lists(self, **kwargs) -> list:
176
+ # This will also set up a compile, for vlog + vsim (with run -a)
177
+ vsim_command_list = [
178
+ self.sim_exe,
179
+ '-c' if self.run_in_batch_mode() else '',
180
+ '-do', 'vsim.do', '-logfile', 'sim.log',
181
+ ]
182
+ return [vsim_command_list]
183
+
184
+ def get_post_simulate_command_lists(self, **kwargs) -> list:
185
+ return []
186
+
187
+ def write_vlog_dot_f(self, filename='vlog.f') -> None:
188
+ '''Returns none, creates filename (str) for a vlog.f'''
189
+ vlog_dot_f_lines = []
190
+
191
+ # Add compile args from config.tool.TOOL (questa, etc):
192
+ vlog_dot_f_lines += self.tool_config.get(
193
+ 'compile-args',
194
+ '-sv -svinputport=net -lint').split()
195
+ # Add waivers from config.tool.TOOL (questa, modelsim_ase, etc)
196
+ for waiver in self.tool_config.get(
197
+ 'compile-waivers',
198
+ [ #defaults:
199
+ '2275', # 2275 - Existing package 'foo_pkg' will be overwritten.
200
+ ]) + self.args['compile-waivers']:
201
+ vlog_dot_f_lines += ['-suppress', str(waiver)]
202
+
203
+ if self.args['gui'] or self.args['waves']:
204
+ vlog_dot_f_lines += self.tool_config.get('compile-waves-args', '').split()
205
+
206
+ vlog_dot_f_fname = filename
207
+ vlog_dot_f_fpath = os.path.join(self.args['work-dir'], vlog_dot_f_fname)
208
+
209
+ for value in self.incdirs:
210
+ vlog_dot_f_lines += [ f"+incdir+{value}" ]
211
+
212
+ for k,v in self.defines.items():
213
+ if v is None:
214
+ vlog_dot_f_lines += [ f'+define+{k}' ]
215
+ else:
216
+
217
+ # if the value v is a double-quoted string, such as v='"hi"', the
218
+ # entire +define+NAME="hi" needs to wrapped in double quotes with the
219
+ # value v double-quotes escaped: "+define+NAME=\"hi\""
220
+ if isinstance(v, str) and v.startswith('"') and v.endswith('"'):
221
+ str_v = v.replace('"', '\\"')
222
+ vlog_dot_f_lines += [ f'"+define+{k}={str_v}"' ]
223
+ else:
224
+ # Generally we should only support int and str python types passed as
225
+ # +define+{k}={v}, but also for SystemVerilog plusargs
226
+ vlog_dot_f_lines += [ f'+define+{k}={sanitize_defines_for_sh(v)}' ]
227
+
228
+
229
+ vlog_dot_f_lines += self.args['compile-args']
230
+
231
+ vlog_dot_f_lines += [
232
+ '-source',
233
+ ] + list(self.files_sv) + list(self.files_v)
234
+
235
+ if not self.files_sv and not self.files_v:
236
+ if not self.args['stop-before-compile']:
237
+ self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
238
+ 'cannot create a valid vlog.f')
239
+
240
+ with open(vlog_dot_f_fpath, 'w', encoding='utf-8') as f:
241
+ f.writelines(line + "\n" for line in vlog_dot_f_lines)
242
+
243
+ def vopt_handle_parameters(self) -> (str, list):
244
+ '''Returns str for vopt or voptargs, and list of vopt tcl
245
+
246
+ Note this is used for self.use_vopt = True or False.
247
+ '''
248
+
249
+ voptargs_str = ''
250
+ vopt_do_lines = []
251
+
252
+ # Note that if self.use_vopt=True, we have to do some workarounds for how
253
+ # some questa-like tools behave for: tcl/.do + vopt arg processing
254
+ # This affects string based parameters that have spaces (vopt treats spaces unique args,
255
+ # vsim does not). Since we'd like to keep the vopt/vsim split into separate steps, we can
256
+ # work around this by setting tcl varaibles for each parameter.
257
+ if self.parameters:
258
+ if not self.use_vopt:
259
+ voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
260
+ else:
261
+ for k,v in self.parameters.items():
262
+ s = sim.parameters_dict_get_command_list(params={k: v}, arg_prefix='')[0]
263
+ # At this point, s should be a str in form {k}={v}
264
+ if not s or '=' not in s:
265
+ continue
266
+ if ' ' in s:
267
+ # Instead of:
268
+ # vopt -GMyParam="hi bye"
269
+ # we'll do:
270
+ # set PARAMETERS(MyParam) "hi bye"
271
+ # vopt -GMyParam=$PARAMETERS(MyParam)
272
+ s = s.replace(f'{k}=', f'set PARAMETERS({k}) ')
273
+ vopt_do_lines.append(s)
274
+ voptargs_str += f' -G{k}=$PARAMETERS({k}) '
275
+ else:
276
+ voptargs_str += f' -G{s} '
277
+
278
+ return voptargs_str, vopt_do_lines
279
+
280
+
281
+ def write_vsim_dot_do( # pylint: disable=too-many-locals
282
+ self, dot_do_to_write: list
283
+ ) -> None:
284
+ '''Writes files(s) based on dot_do_to_write(list of str)
285
+
286
+ list arg values can be empty (all) or have items 'all', 'sim', 'lint', 'vlog'.'''
287
+
288
+ vsim_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim.do')
289
+ vsim_lintonly_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim_lintonly.do')
290
+ vsim_vlogonly_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim_vlogonly.do')
291
+
292
+ sim_plusargs_str = self._get_sim_plusargs_str()
293
+ vsim_suppress_list_str = self._get_vsim_suppress_list_str()
294
+ vsim_ext_args = ' '.join(self.args.get('sim-args', []))
295
+
296
+ voptargs_str = self.tool_config.get('elab-args', '')
297
+ voptargs_str += ' '.join(self.args.get('elab-args', []))
298
+ if self.args['gui'] or self.args['waves']:
299
+ voptargs_str += ' ' + self.tool_config.get('simulate-waves-args', '+acc')
300
+ util.artifacts.add_extension(
301
+ search_paths=self.args['work-dir'], file_extension='wlf',
302
+ typ='waveform', description='Modelsim/Questa Waveform WLF (Wave Log Format) file'
303
+ )
304
+
305
+ # TODO(drew): support self.args['sim_libary'] (1 lists)
306
+ vlog_do_lines = []
307
+ vsim_do_lines = []
308
+
309
+ # parameters, use helper method to get voptargs_str and vopt_do_lines
310
+ more_voptargs_str, vopt_do_lines = self.vopt_handle_parameters()
311
+ voptargs_str += more_voptargs_str
312
+
313
+
314
+ vopt_one_liner = ""
315
+ if self.use_vopt:
316
+ vopt_one_liner = (
317
+ f"vopt {voptargs_str} work.{self.args['top']} -o opt__{self.args['top']}"
318
+ )
319
+ vopt_one_liner = vopt_one_liner.replace('\n', ' ') # needs to be a one-liner
320
+ # vopt doesn't need -voptargs=(value) like vsim does, simply use (value).
321
+ vopt_one_liner = vopt_one_liner.replace('-voptargs=', '')
322
+
323
+ vsim_one_liner = "vsim -onfinish stop" \
324
+ + f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
325
+ + f" {vsim_ext_args} opt__{self.args['top']}"
326
+ else:
327
+ # vopt doesn't exist, use single vsim call after vlog call:
328
+ vsim_one_liner = "vsim -onfinish stop" \
329
+ + f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
330
+ + f" {voptargs_str} {vsim_ext_args} work.{self.args['top']}"
331
+
332
+
333
+ vsim_one_liner = vsim_one_liner.replace('\n', ' ')
334
+
335
+ vlog_do_lines += [
336
+ "if {[file exists work]} { vdel -all work; }",
337
+ "vlib work;",
338
+ "quietly set qc 30;",
339
+ "if {[catch {vlog -f vlog.f} result]} {",
340
+ " echo \"Caught $result \";",
341
+ " if {[batch_mode]} {",
342
+ " quit -f -code 20;",
343
+ " }",
344
+ "}",
345
+ ]
346
+
347
+ if self.use_vopt:
348
+ vopt_do_lines += [
349
+ "if {[catch { " + vopt_one_liner + " } result] } {",
350
+ " echo \"Caught $result\";",
351
+ " if {[batch_mode]} {",
352
+ " quit -f -code 19;",
353
+ " }",
354
+ "}",
355
+ ]
356
+
357
+ vsim_do_lines += [
358
+ "if {[catch { " + vsim_one_liner + " } result] } {",
359
+ " echo \"Caught $result\";",
360
+ " if {[batch_mode]} {",
361
+ " quit -f -code 18;",
362
+ " }",
363
+ "}",
364
+ ]
365
+
366
+ vsim_vlogonly_dot_do_lines = vlog_do_lines + [
367
+ "if {[batch_mode]} {",
368
+ " quit -f -code 0;",
369
+ "}",
370
+ ]
371
+
372
+ final_check_teststatus_do_lines = [
373
+ "set TestStatus [coverage attribute -name SEED -name TESTSTATUS];",
374
+ "if {[regexp \"TESTSTATUS += 0\" $TestStatus]} {",
375
+ " quietly set qc 0;",
376
+ "} elseif {[regexp \"TESTSTATUS += 1\" $TestStatus]} {",
377
+ " quietly set qc 0;",
378
+ "} else {",
379
+ " quietly set qc 2;",
380
+ "}",
381
+ "if {[batch_mode]} {",
382
+ " quit -f -code $qc;",
383
+ "}",
384
+ ]
385
+
386
+ # final vlog/vopt/vsim lint-only .do command (want to make sure it can completely
387
+ # build for 'elab' style eda job), runs for 0ns, logs nothing for a waveform, quits
388
+ vsim_lintonly_dot_do_lines = vlog_do_lines + vopt_do_lines + vsim_do_lines \
389
+ + final_check_teststatus_do_lines
390
+
391
+ # final vlog/opt/vsim full simulation .do command.
392
+ vsim_dot_do_lines = vlog_do_lines + vopt_do_lines + vsim_do_lines + [
393
+ "onbreak { resume; };",
394
+ "catch {log -r *};",
395
+ "run -a;",
396
+ ] + final_check_teststatus_do_lines
397
+
398
+ write_all = len(dot_do_to_write) == 0 or 'all' in dot_do_to_write
399
+ if write_all or 'sim' in dot_do_to_write:
400
+ with open(vsim_dot_do_fpath, 'w', encoding='utf-8') as f:
401
+ f.writelines(line + "\n" for line in vsim_dot_do_lines)
402
+
403
+ if write_all or 'lint' in dot_do_to_write:
404
+ with open(vsim_lintonly_dot_do_fpath, 'w', encoding='utf-8') as f:
405
+ f.writelines(line + "\n" for line in vsim_lintonly_dot_do_lines)
406
+
407
+ if write_all or 'vlog' in dot_do_to_write:
408
+ with open(vsim_vlogonly_dot_do_fpath, 'w', encoding='utf-8') as f:
409
+ f.writelines(line + "\n" for line in vsim_vlogonly_dot_do_lines)
410
+
411
+
412
+ def _get_sim_plusargs_str(self) -> str:
413
+ sim_plusargs = []
414
+
415
+ assert isinstance(self.args["sim-plusargs"], list), \
416
+ f'{self.target=} {type(self.args["sim-plusargs"])=} but must be list'
417
+
418
+ for x in self.args['sim-plusargs']:
419
+ # For vsim we need to add a +key=value if the + is missing
420
+ if x[0] != '+':
421
+ x = f'+{x}'
422
+ sim_plusargs.append(x)
423
+
424
+ return ' '.join(sim_plusargs)
425
+
426
+
427
+ def _get_vsim_suppress_list_str(self) -> str:
428
+ vsim_suppress_list = []
429
+ # Add waivers from config.tool.TOOL:
430
+ for waiver in self.tool_config.get(
431
+ 'simulate-waivers', [
432
+ #defaults:
433
+ '3009', # 3009: [TSCALE] - Module 'foo' does not have a timeunit/timeprecision
434
+ # specification in effect, but other modules do.
435
+ ]) + self.args['sim-waivers']:
436
+ vsim_suppress_list += ['-suppress', str(waiver)]
437
+
438
+ return ' '.join(vsim_suppress_list)
439
+
440
+
441
+ def artifacts_add(self, name: str, typ: str, description: str) -> None:
442
+ '''Override from Command.artifacts_add, so we can catch known file
443
+
444
+ names to make their typ/description better, such as CommandSim using
445
+ sim.log
446
+ '''
447
+ _, leafname = os.path.split(name)
448
+ if leafname == 'sim.log':
449
+ description = 'Modelsim/Questa Transcript log file'
450
+
451
+ super().artifacts_add(name=name, typ=typ, description=description)
452
+
453
+
454
+ class CommonElabQuesta(CommonSimQuesta):
455
+ '''CommonElabQuesta is a command handler for: eda elab --tool=(questa family)'''
456
+
457
+ command_name = 'elab'
458
+
459
+ def __init__(self, config:dict):
460
+ super().__init__(config)
461
+ self.args['stop-after-elaborate'] = True
462
+
463
+
464
+ class CommonLintQuesta(CommonSimQuesta):
465
+ '''CommonSimQuesta is a command handler for: eda lint --tool=(questa family)'''
466
+
467
+ command_name = 'lint'
468
+
469
+ def __init__(self, config:dict):
470
+ super().__init__(config)
471
+ self.args['stop-after-compile'] = True
472
+ self.args['stop-after-elaborate'] = True
473
+
474
+
475
+ class CommonFListQuesta(CommandFList, ToolQuesta):
476
+ '''CommonFListQuesta is a command handler for: eda flist --tool=(questa family)'''
477
+
478
+ def __init__(self, config: dict):
479
+ CommandFList.__init__(self, config=config)
480
+ ToolQuesta.__init__(self, config=self.config)
@@ -0,0 +1,84 @@
1
+ ''' opencos.tools.questa - Used by opencos.eda for sim/elab commands w/ --tool=questa.
2
+
3
+ Contains classes for CommandSimQuesta, CommandElabQuesta.
4
+ For: Questa Intel (FPGA) Edition-64 vsim 20XX.X Simulator
5
+
6
+ Note - NOT the starter edition (see questa_fse.py)
7
+
8
+ '''
9
+
10
+ # pylint: disable=R0801 # (setting similar, but not identical, self.defines key/value pairs)
11
+
12
+ # TODO(drew): fix these pylint eventually:
13
+ # pylint: disable=too-many-branches, too-many-ancestors
14
+
15
+ import os
16
+
17
+ from opencos.tools.questa_common import CommonSimQuesta, CommonFListQuesta
18
+
19
+
20
+ class CommandSimQuestaFe(CommonSimQuesta):
21
+ '''CommandSimQuestaFe is a command handler for: eda sim --tool=questa_fe
22
+
23
+ Note this inherits 99% from CommonSimQuesta for command handling
24
+ '''
25
+ _TOOL = 'questa_fe'
26
+ _EXE = 'vsim'
27
+ use_vopt = True
28
+
29
+ def __init__(self, config: dict):
30
+ # this will setup with self._TOOL = questa, optionally repair it later
31
+ CommonSimQuesta.__init__(self, config=config)
32
+
33
+ # repairs: override self._TOOL, and run get_versions() again.
34
+ self._TOOL = 'questa_fe'
35
+
36
+ self.shell_command = os.path.join(self.sim_exe_base_path, 'vsim')
37
+ self.starter_edition = False
38
+ self.args.update({
39
+ 'tool': self._TOOL, # override
40
+ 'gui': False,
41
+ })
42
+
43
+
44
+ def set_tool_defines(self):
45
+ '''Override from questa.ToolQuesta'''
46
+ # Update any defines from config.tools.questa_fse:
47
+ self.defines.update(
48
+ self.tool_config.get(
49
+ 'defines',
50
+ # defaults, if not set:
51
+ {
52
+ 'OC_TOOL_QUESTA_FE': 1
53
+ }
54
+ )
55
+ )
56
+
57
+
58
+ class CommandElabQuestaFe(CommandSimQuestaFe):
59
+ '''CommandElabQuesta is a command handler for: eda elab --tool=questa_fe'''
60
+
61
+ command_name = 'elab'
62
+
63
+ def __init__(self, config:dict):
64
+ super().__init__(config)
65
+ self.args['stop-after-elaborate'] = True
66
+
67
+
68
+ class CommandLintQuestaFe(CommandSimQuestaFe):
69
+ '''CommandLintQuesta is a command handler for: eda lint --tool=questa_fe'''
70
+
71
+ command_name = 'lint'
72
+
73
+ def __init__(self, config:dict):
74
+ super().__init__(config)
75
+ self.args['stop-after-compile'] = True
76
+ self.args['stop-after-elaborate'] = True
77
+
78
+
79
+ class CommandFListQuestaFe(CommonFListQuesta):
80
+ '''CommandFListQuesta is a command handler for: eda flist --tool=questa'''
81
+
82
+ def __init__(self, config: dict):
83
+ CommonFListQuesta.__init__(self, config=config)
84
+ self._TOOL = 'questa_fse'
@@ -10,23 +10,22 @@ For: Questa Intel Starter FPGA Edition-64 vsim 20XX.X Simulator
10
10
 
11
11
  import os
12
12
 
13
- from opencos.tools.modelsim_ase import CommandSimModelsimAse
14
- from opencos.tools.questa import CommandFListQuesta
13
+ from opencos.tools.questa_common import CommonSimQuesta, CommonFListQuesta
15
14
 
16
15
 
17
- class CommandSimQuestaFse(CommandSimModelsimAse):
16
+ class CommandSimQuestaFse(CommonSimQuesta):
18
17
  '''CommandSimQuestaFse is a command handler for: eda sim --tool=questa_fse
19
18
 
20
- Note this inherits 99% from CommandSimModelSimAse for command handling
19
+ Note this inherits 99% from CommonSimQuesta for command handling
21
20
  '''
22
21
  _TOOL = 'questa_fse'
23
22
  _EXE = 'vsim'
24
23
  use_vopt = True
25
24
 
26
25
  def __init__(self, config: dict):
27
- # this will setup with self._TOOL = modelsim_ase, which is not ideal so
26
+ # this will setup with self._TOOL = questa, which is not ideal so
28
27
  # we have to repait it later.
29
- CommandSimModelsimAse.__init__(self, config=config)
28
+ CommonSimQuesta.__init__(self, config=config)
30
29
 
31
30
  # repairs: override self._TOOL, and run get_versions() again.
32
31
  self._TOOL = 'questa_fse'
@@ -74,9 +73,9 @@ class CommandLintQuestaFse(CommandSimQuestaFse):
74
73
  self.args['stop-after-elaborate'] = True
75
74
 
76
75
 
77
- class CommandFListQuestaFse(CommandFListQuesta):
76
+ class CommandFListQuestaFse(CommonFListQuesta):
78
77
  '''CommandFListQuestaFse is a command handler for: eda flist --tool=questa_fse'''
79
78
 
80
79
  def __init__(self, config: dict):
81
- CommandFListQuesta.__init__(self, config=config)
80
+ CommonFListQuesta.__init__(self, config=config)
82
81
  self._TOOL = 'questa_fse'
opencos/tools/riviera.py CHANGED
@@ -11,11 +11,12 @@ import shutil
11
11
  import subprocess
12
12
 
13
13
  from opencos import util
14
- from opencos.tools.modelsim_ase import ToolModelsimAse, CommandSimModelsimAse
14
+ from opencos.tools.questa_common import ToolQuesta, CommonSimQuesta
15
+ from opencos.commands import CommandFList
15
16
  from opencos.utils.str_helpers import sanitize_defines_for_sh
16
17
  from opencos.utils import status_constants
17
18
 
18
- class ToolRiviera(ToolModelsimAse):
19
+ class ToolRiviera(ToolQuesta):
19
20
  '''ToolRiviera used by opencos.eda for --tool=riviera'''
20
21
 
21
22
  _TOOL = 'riviera'
@@ -60,14 +61,20 @@ class ToolRiviera(ToolModelsimAse):
60
61
  return self._VERSION
61
62
 
62
63
 
63
- class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
64
+ class CommandSimRiviera(CommonSimQuesta, ToolRiviera):
64
65
  '''CommandSimRiviera is a command handler for: eda sim --tool=riviera'''
65
66
 
66
67
  def __init__(self, config: dict):
67
- CommandSimModelsimAse.__init__(self, config=config)
68
+ CommonSimQuesta.__init__(self, config=config)
69
+
70
+ # This technically inherits ToolQuesta and ToolRiviera, but ToolRiviera will
71
+ # override get_versions(). Just be careful on using issinstance(cls_obj, ToolQuesta),
72
+ # and instead use self._TOOL, or self.args['tool']
68
73
  ToolRiviera.__init__(self, config=self.config)
74
+
69
75
  self.shell_command = os.path.join(self.sim_exe_base_path, 'vsim')
70
- self.starter_edition = True
76
+ self.starter_edition = False
77
+
71
78
  self.args.update({
72
79
  'tool': self._TOOL, # override
73
80
  'gui': False,
@@ -220,7 +227,7 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
220
227
 
221
228
 
222
229
 
223
- def write_vsim_dot_do( # pylint: disable=too-many-branches
230
+ def write_vsim_dot_do( # pylint: disable=too-many-branches,too-many-locals
224
231
  self, dot_do_to_write: list
225
232
  ) -> None:
226
233
  '''Writes files(s) based on dot_do_to_write(list of str)
@@ -247,19 +254,22 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
247
254
  voptargs_str += self.tool_config.get('simulate-waves-args',
248
255
  '+accb +accr +access +r+w')
249
256
  if self.args['coverage']:
250
- voptargs_str += self.tool_config.get('coverage-args', '')
257
+ voptargs_str += ' ' + self.tool_config.get('coverage-args', '')
258
+
259
+ if self.args['uvm']:
260
+ if all(x not in voptargs_str for x in ('+access +r', '+access +w+r')):
261
+ voptargs_str += ' +access +r'
251
262
 
252
263
  # parameters
253
264
  if self.parameters:
254
265
  voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
255
266
 
256
- # TODO(drew): support self.args['sim_libary', 'elab-args', sim-args'] (3 lists)
257
- # to add to vsim_one_liner.
267
+ vsim_libs = ' '.join([f'-l {x}' for x in self.args['sim-library']])
258
268
 
259
269
  vsim_one_liner = (
260
270
  "vsim"
261
271
  f" -sv_seed {self.args['seed']} {sim_plusargs_str}"
262
- f" {voptargs_str} {vsim_ext_args} work.{self.args['top']}"
272
+ f" {voptargs_str} {vsim_ext_args} {vsim_libs} work.{self.args['top']}"
263
273
  )
264
274
 
265
275
  vsim_one_liner = vsim_one_liner.replace('\n', ' ') # needs to be a one-liner
@@ -386,3 +396,10 @@ class CommandLintRiviera(CommandSimRiviera):
386
396
  super().__init__(config)
387
397
  self.args['stop-after-compile'] = True
388
398
  self.args['stop-after-elaborate'] = True
399
+
400
+ class CommandFListRiviera(CommandFList, ToolRiviera):
401
+ '''CommonFListQuesta is a command handler for: eda flist --tool=riviera'''
402
+
403
+ def __init__(self, config: dict):
404
+ CommandFList.__init__(self, config=config)
405
+ ToolRiviera.__init__(self, config=self.config)