opencos-eda 0.2.48__py3-none-any.whl → 0.2.50__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 (58) hide show
  1. opencos/__init__.py +4 -2
  2. opencos/_version.py +10 -7
  3. opencos/commands/flist.py +8 -7
  4. opencos/commands/multi.py +14 -15
  5. opencos/commands/sim.py +5 -0
  6. opencos/commands/sweep.py +3 -2
  7. opencos/deps/__init__.py +0 -0
  8. opencos/deps/defaults.py +69 -0
  9. opencos/deps/deps_commands.py +419 -0
  10. opencos/deps/deps_file.py +326 -0
  11. opencos/deps/deps_processor.py +670 -0
  12. opencos/deps_schema.py +7 -8
  13. opencos/eda.py +84 -64
  14. opencos/eda_base.py +585 -316
  15. opencos/eda_config.py +85 -14
  16. opencos/eda_config_defaults.yml +36 -4
  17. opencos/eda_extract_targets.py +22 -14
  18. opencos/eda_tool_helper.py +33 -7
  19. opencos/export_helper.py +166 -86
  20. opencos/export_json_convert.py +31 -23
  21. opencos/files.py +2 -1
  22. opencos/hw/__init__.py +0 -0
  23. opencos/{oc_cli.py → hw/oc_cli.py} +9 -4
  24. opencos/names.py +0 -4
  25. opencos/peakrdl_cleanup.py +13 -7
  26. opencos/seed.py +19 -11
  27. opencos/tests/helpers.py +3 -2
  28. opencos/tests/test_deps_helpers.py +35 -32
  29. opencos/tests/test_eda.py +36 -29
  30. opencos/tests/test_eda_elab.py +7 -4
  31. opencos/tests/test_eda_synth.py +1 -1
  32. opencos/tests/test_oc_cli.py +1 -1
  33. opencos/tests/test_tools.py +4 -2
  34. opencos/tools/iverilog.py +2 -2
  35. opencos/tools/modelsim_ase.py +24 -2
  36. opencos/tools/questa.py +5 -3
  37. opencos/tools/questa_fse.py +57 -0
  38. opencos/tools/riviera.py +1 -1
  39. opencos/tools/slang.py +9 -3
  40. opencos/tools/surelog.py +1 -1
  41. opencos/tools/verilator.py +26 -1
  42. opencos/tools/vivado.py +34 -27
  43. opencos/tools/yosys.py +4 -3
  44. opencos/util.py +532 -474
  45. opencos/utils/__init__.py +0 -0
  46. opencos/utils/markup_helpers.py +98 -0
  47. opencos/utils/str_helpers.py +111 -0
  48. opencos/utils/subprocess_helpers.py +108 -0
  49. {opencos_eda-0.2.48.dist-info → opencos_eda-0.2.50.dist-info}/METADATA +1 -1
  50. opencos_eda-0.2.50.dist-info/RECORD +89 -0
  51. {opencos_eda-0.2.48.dist-info → opencos_eda-0.2.50.dist-info}/entry_points.txt +1 -1
  52. opencos/deps_helpers.py +0 -1346
  53. opencos_eda-0.2.48.dist-info/RECORD +0 -79
  54. /opencos/{pcie.py → hw/pcie.py} +0 -0
  55. {opencos_eda-0.2.48.dist-info → opencos_eda-0.2.50.dist-info}/WHEEL +0 -0
  56. {opencos_eda-0.2.48.dist-info → opencos_eda-0.2.50.dist-info}/licenses/LICENSE +0 -0
  57. {opencos_eda-0.2.48.dist-info → opencos_eda-0.2.50.dist-info}/licenses/LICENSE.spdx +0 -0
  58. {opencos_eda-0.2.48.dist-info → opencos_eda-0.2.50.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,8 @@
1
1
  ''' opencos.tools.modelsim_ase - Used by opencos.eda for sim/elab commands w/ --tool=modelsim_ase.
2
2
 
3
3
  Contains classes for ToolModelsimAse, CommandSimModelsimAse, CommandElabModelsimAse.
4
+
5
+ Note that this is for 32-bit Modelsim Student Edition. Consider using --tool=questa_fse instead.
4
6
  '''
5
7
 
6
8
  # pylint: disable=R0801 # (duplicate code in derived classes, such as if-condition return.)
@@ -8,9 +10,9 @@ Contains classes for ToolModelsimAse, CommandSimModelsimAse, CommandElabModelsim
8
10
  import os
9
11
 
10
12
  from opencos import util
11
- from opencos.util import sanitize_defines_for_sh
12
13
  from opencos.commands import CommandSim
13
14
  from opencos.tools.questa import ToolQuesta
15
+ from opencos.utils.str_helpers import sanitize_defines_for_sh
14
16
 
15
17
  class ToolModelsimAse(ToolQuesta):
16
18
  '''ToolModelsimAse used by opencos.eda for --tool=modelsim_ase'''
@@ -77,7 +79,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
77
79
  command_lists = [['./pre_compile_dep_shell_commands.sh']] + vsim_command_lists
78
80
  )
79
81
 
80
- util.write_eda_config_and_args(dirpath=self.args['work-dir'], command_obj_ref=self)
82
+ self.write_eda_config_and_args()
81
83
 
82
84
  def compile(self):
83
85
  if self.args['stop-before-compile']:
@@ -151,6 +153,9 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
151
153
  ]):
152
154
  vlog_dot_f_lines += ['-suppress', str(waiver)]
153
155
 
156
+ if self.args['gui'] or self.args['waves']:
157
+ vlog_dot_f_lines += self.tool_config.get('compile-waves-args', '').split()
158
+
154
159
  vlog_dot_f_fname = filename
155
160
  vlog_dot_f_fpath = os.path.join(self.args['work-dir'], vlog_dot_f_fname)
156
161
 
@@ -203,6 +208,10 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
203
208
  voptargs_str = ""
204
209
  if self.args['gui'] or self.args['waves']:
205
210
  voptargs_str = self.tool_config.get('simulate-waves-args', '+acc')
211
+ util.artifacts.add_extension(
212
+ search_paths=self.args['work-dir'], file_extension='wlf',
213
+ typ='waveform', description='Modelsim/Questa Waveform WLF (Wave Log Format) file'
214
+ )
206
215
 
207
216
  # TODO(drew): support self.args['sim_libary', 'elab-args', sim-args'] (3 lists)
208
217
  # to add to vsim_one_liner.
@@ -331,6 +340,19 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
331
340
  return ' '.join(vsim_suppress_list)
332
341
 
333
342
 
343
+ def artifacts_add(self, name: str, typ: str, description: str) -> None:
344
+ '''Override from Command.artifacts_add, so we can catch known file
345
+
346
+ names to make their typ/description better, such as CommandSim using
347
+ sim.log
348
+ '''
349
+ _, leafname = os.path.split(name)
350
+ if leafname == 'sim.log':
351
+ description = 'Modelsim/Questa Transcript log file'
352
+
353
+ super().artifacts_add(name=name, typ=typ, description=description)
354
+
355
+
334
356
  class CommandElabModelsimAse(CommandSimModelsimAse):
335
357
  '''CommandElabModelsimAse is a command handler for: eda elab --tool=modelsim_ase'''
336
358
 
opencos/tools/questa.py CHANGED
@@ -40,9 +40,11 @@ class ToolQuesta(Tool):
40
40
  self.error(f"{self._EXE} not in path, need to setup",
41
41
  "(i.e. source /opt/intelFPGA_pro/23.4/settings64.sh")
42
42
  util.debug(f"{path=}")
43
- if self._EXE.endswith('qrun') and 'modelsim_ase' in path:
44
- util.warning(f"{self._EXE=} Questa path is for starter edition (modelsim_ase),",
45
- "consider using --tool modelsim_ase")
43
+ if self._EXE.endswith('qrun') and \
44
+ any(x in path for x in ('modelsim_ase', 'questa_fse')):
45
+ util.warning(f"{self._EXE=} Questa path is for starter edition",
46
+ "(modelsim_ase, questa_fse), consider using --tool=modelsim_ase",
47
+ "or --tool=questa_fse")
46
48
  else:
47
49
  self.sim_exe = path
48
50
  self.sim_exe_base_path, _ = os.path.split(path)
@@ -0,0 +1,57 @@
1
+ ''' opencos.tools.questa_fse - Used by opencos.eda for sim/elab commands w/ --tool=questa_fse.
2
+
3
+ Contains classes for CommandSimQuestaFse, CommandElabQuestaFse.
4
+ '''
5
+
6
+ # pylint: disable=R0801 # (duplicate code in derived classes, such as if-condition return.)
7
+ # pylint: disable=too-many-ancestors
8
+
9
+ import os
10
+
11
+ from opencos.tools.modelsim_ase import CommandSimModelsimAse
12
+
13
+
14
+ class CommandSimQuestaFse(CommandSimModelsimAse):
15
+ '''CommandSimQuestaFse is a command handler for: eda sim --tool=questa_fse
16
+
17
+ Note this inherits 99% from CommandSimModelSimAse for command handling
18
+ '''
19
+ _TOOL = 'questa_fse'
20
+ _EXE = 'vsim'
21
+
22
+ def __init__(self, config: dict):
23
+ # this will setup with self._TOOL = modelsim_ase, which is not ideal so
24
+ # we have to repait it later.
25
+ CommandSimModelsimAse.__init__(self, config=config)
26
+
27
+ # repairs: override self._TOOL, and run get_versions() again.
28
+ self._TOOL = 'questa_fse'
29
+
30
+ self.shell_command = os.path.join(self.sim_exe_base_path, 'vsim')
31
+ self.starter_edition = True
32
+ self.args.update({
33
+ 'tool': self._TOOL, # override
34
+ 'gui': False,
35
+ })
36
+
37
+
38
+ def set_tool_defines(self):
39
+ '''Override from questa.ToolQuesta'''
40
+ # Update any defines from config.tools.questa_fse:
41
+ self.defines.update(
42
+ self.tool_config.get(
43
+ 'defines',
44
+ # defaults, if not set:
45
+ {
46
+ 'OC_TOOL_QUESTA_FSE': 1
47
+ }
48
+ )
49
+ )
50
+
51
+
52
+ class CommandElabQuestaFse(CommandSimQuestaFse):
53
+ '''CommandElabQuestaFse is a command handler for: eda elab --tool=questa_fse'''
54
+
55
+ def __init__(self, config:dict):
56
+ super().__init__(config)
57
+ self.args['stop-after-elaborate'] = True
opencos/tools/riviera.py CHANGED
@@ -11,8 +11,8 @@ import shutil
11
11
  import subprocess
12
12
 
13
13
  from opencos import util
14
- from opencos.util import sanitize_defines_for_sh
15
14
  from opencos.tools.modelsim_ase import ToolModelsimAse, CommandSimModelsimAse
15
+ from opencos.utils.str_helpers import sanitize_defines_for_sh
16
16
 
17
17
  class ToolRiviera(ToolModelsimAse):
18
18
  '''ToolRiviera used by opencos.eda for --tool=riviera'''
opencos/tools/slang.py CHANGED
@@ -10,9 +10,9 @@ import shutil
10
10
  import subprocess
11
11
 
12
12
  from opencos import util
13
- from opencos.util import sanitize_defines_for_sh
14
13
  from opencos.eda_base import Tool
15
14
  from opencos.commands import CommandElab
15
+ from opencos.utils.str_helpers import sanitize_defines_for_sh
16
16
 
17
17
 
18
18
  class ToolSlang(Tool):
@@ -191,14 +191,20 @@ class CommandElabSlang(CommandElab, ToolSlang):
191
191
 
192
192
  return command_list
193
193
 
194
- def _get_slang_json_args(self, command_exe:str) -> list:
194
+ def _get_slang_json_args(self, command_exe: str) -> list:
195
195
  command_list = []
196
196
 
197
- if self.args.get('slang-json', False) and command_exe == 'slang':
197
+ _, command_exe_leaf = os.path.split(command_exe)
198
+ if self.args.get('slang-json', False) and command_exe_leaf == 'slang':
198
199
  for arg in self.all_json_args:
199
200
  if arg not in command_list:
200
201
  command_list.append(arg)
201
202
  if arg == '--ast-json': # needs filename
202
203
  command_list.append('slang.json')
204
+ util.artifacts.add(
205
+ name=os.path.join(self.args['work-dir'], 'slang.json'),
206
+ typ='json',
207
+ description='Abstract syntax tree from slang --ast-json'
208
+ )
203
209
 
204
210
  return command_list
opencos/tools/surelog.py CHANGED
@@ -7,9 +7,9 @@ import shutil
7
7
  import subprocess
8
8
 
9
9
  from opencos import util
10
- from opencos.util import sanitize_defines_for_sh
11
10
  from opencos.eda_base import Tool
12
11
  from opencos.commands import CommandElab
12
+ from opencos.utils.str_helpers import sanitize_defines_for_sh
13
13
 
14
14
 
15
15
  class ToolSurelog(Tool):
@@ -10,9 +10,9 @@ import shutil
10
10
  import subprocess
11
11
 
12
12
  from opencos import util
13
- from opencos.util import sanitize_defines_for_sh
14
13
  from opencos.eda_base import Tool
15
14
  from opencos.commands import CommandSim
15
+ from opencos.utils.str_helpers import sanitize_defines_for_sh
16
16
 
17
17
  class ToolVerilator(Tool):
18
18
  '''ToolVerilator used by opencos.eda for --tool=verilator'''
@@ -346,6 +346,16 @@ class VerilatorSim(CommandSim, ToolVerilator):
346
346
  util.info(f'--waves arg present, no $dumpfile found, adding SV file: {file_to_add}')
347
347
  self.add_file(file_to_add)
348
348
 
349
+ # register .vcd or .fst artifacts:
350
+ util.artifacts.add_extension(
351
+ search_paths=self.args['work-dir'], file_extension='fst',
352
+ typ='waveform', description='Simulation Waveform FST (Fast Signal Trace) file'
353
+ )
354
+ util.artifacts.add_extension(
355
+ search_paths=self.args['work-dir'], file_extension='vcd',
356
+ typ='waveform', description='Simulation Waveform VCD (Value Change Dump) file'
357
+ )
358
+
349
359
 
350
360
  def _get_start_verilator_command_list(self, lint_only: bool = False) -> list:
351
361
 
@@ -447,6 +457,21 @@ class VerilatorSim(CommandSim, ToolVerilator):
447
457
  return verilate_args
448
458
 
449
459
 
460
+ def artifacts_add(self, name: str, typ: str, description: str) -> None:
461
+ '''Override from Command.artifacts_add, so we can catch known file
462
+
463
+ names to make their typ/description better, such as CommandSim using
464
+ sim.log or compile.log
465
+ '''
466
+ _, leafname = os.path.split(name)
467
+ if leafname == 'sim.log':
468
+ description = 'Verilated executable log from stdout/stderr'
469
+ elif leafname == 'compile.log':
470
+ description = 'Verilator compile step log from verilator call'
471
+
472
+ super().artifacts_add(name=name, typ=typ, description=description)
473
+
474
+
450
475
  class VerilatorElab(VerilatorSim):
451
476
  '''VerilatorElab is a command handler for: eda elab --tool=verilator'''
452
477
 
opencos/tools/vivado.py CHANGED
@@ -63,29 +63,14 @@ class ToolVivado(Tool):
63
63
  util.info("environment for XILINX_VIVADO is not set or doesn't match the vivado path:",
64
64
  f"XILINX_VIVADO={xilinx_vivado} EXE PATH={self.vivado_exe}")
65
65
 
66
- version = None
67
- # Note this is commented out b/c it's a bit slow, up to 1.0 second to
68
- # run their tool just to query the version information.
69
- # Do this if you need the extra minor version like 2024.2.1.
70
- #try:
71
- # # Get version from vivado -version, or xsim --version:
72
- # vivado_ret = subprocess.run(['vivado', '-version'], capture_output=True)
73
- # lines = vivado_ret.stdout.decode('utf-8', errors='replace').split('\n')
74
- # words = lines[0].split() # vivado v2024.2.1 (64-bit)
75
- # version = words[1][1:] # 2024.2.1
76
- # self._VERSION = version
77
- #except:
78
- # pass
79
-
80
- if not version:
81
- # Get version based on install path name:
82
- util.debug(f"vivado path = {self.vivado_exe}")
83
- m = re.search(r'(\d\d\d\d)\.(\d)', self.vivado_exe)
84
- if m:
85
- version = m.group(1) + '.' + m.group(2)
86
- self._VERSION = version
87
- else:
88
- self.error("Vivado path doesn't specificy version, expecting (dddd.d)")
66
+ # Get version based on install path name. Calling vivado -verison is too slow.
67
+ util.debug(f"vivado path = {self.vivado_exe}")
68
+ m = re.search(r'(\d\d\d\d)\.(\d)', self.vivado_exe)
69
+ if m:
70
+ version = m.group(1) + '.' + m.group(2)
71
+ self._VERSION = version
72
+ else:
73
+ self.error("Vivado path doesn't specificy version, expecting (dddd.d)")
89
74
 
90
75
  if version:
91
76
  numbers_list = version.split('.')
@@ -182,7 +167,7 @@ class CommandSimVivado(CommandSim, ToolVivado):
182
167
  ['./simulate.sh'],
183
168
  ])
184
169
 
185
- util.write_eda_config_and_args(dirpath=self.args['work-dir'], command_obj_ref=self)
170
+ self.write_eda_config_and_args()
186
171
 
187
172
  def compile(self):
188
173
  if self.args['stop-before-compile']:
@@ -260,6 +245,14 @@ class CommandSimVivado(CommandSim, ToolVivado):
260
245
  def get_simulate_command_lists(self, **kwargs) -> list:
261
246
  # create TCL
262
247
  tcl_name = os.path.abspath(os.path.join(self.args['work-dir'], self.args['tcl-file']))
248
+
249
+ if self.args['waves']:
250
+ util.artifacts.add_extension(
251
+ search_paths=self.args['work-dir'], file_extension='wdb',
252
+ typ='waveform', description='Vivado XSim Waveform WDB (Wave DataBase) file'
253
+ )
254
+
255
+
263
256
  with open( tcl_name, 'w', encoding='utf-8' ) as fo:
264
257
  if self.args['waves']:
265
258
  if self.args['waves-start']:
@@ -345,6 +338,23 @@ class CommandSimVivado(CommandSim, ToolVivado):
345
338
  self.files_v.insert(0, glbl_v)
346
339
 
347
340
 
341
+ def artifacts_add(self, name: str, typ: str, description: str) -> None:
342
+ '''Override from Command.artifacts_add, so we can catch known file
343
+
344
+ names to make their typ/description better, such as CommandSim using
345
+ sim.log or compile.log
346
+ '''
347
+ _, leafname = os.path.split(name)
348
+ if leafname == 'xsim.log':
349
+ description = 'Vivado XSim simulation step (3/3) log from stdout/stderr'
350
+ elif leafname == 'xelab.log':
351
+ description = 'Vivado XSim elaboration step (2/3) log from stdout/stderr'
352
+ elif leafname == 'xvlog.log':
353
+ description = 'Vivado XSim compile step (1/3) log from stdout/stderr'
354
+
355
+ super().artifacts_add(name=name, typ=typ, description=description)
356
+
357
+
348
358
  class CommandElabVivado(CommandSimVivado):
349
359
  '''CommandElabVivado is a command handler for: eda elab --tool=vivado, uses xvlog, xelab'''
350
360
  def __init__(self, config: dict):
@@ -933,9 +943,6 @@ class CommandUploadVivado(CommandUpload, ToolVivado):
933
943
  util.info("Upload done")
934
944
 
935
945
 
936
-
937
-
938
-
939
946
  class CommandOpenVivado(CommandOpen, ToolVivado):
940
947
  '''CommandOpenVivado command handler class used by: eda open --tool vivado'''
941
948
  def __init__(self, config: dict):
opencos/tools/yosys.py CHANGED
@@ -9,9 +9,10 @@ import os
9
9
  import shutil
10
10
  import subprocess
11
11
 
12
- from opencos import util
12
+ from opencos import util, eda_config
13
13
  from opencos.eda_base import Tool, get_eda_exec
14
14
  from opencos.commands import CommandSynth, CommandLec
15
+ from opencos.utils.markup_helpers import yaml_safe_load
15
16
 
16
17
 
17
18
  def get_commands_to_run_scriptfiles(
@@ -543,8 +544,8 @@ class CommandLecYosys(CommandLec, ToolYosys):
543
544
  '''Returns the top name given the design number that we synthesized'''
544
545
 
545
546
  work_dir = self.synth_work_dirs[design_num]
546
- output_cfg_fpath = os.path.join(work_dir, util.EDA_OUTPUT_CONFIG_FNAME)
547
- data = util.yaml_safe_load(output_cfg_fpath)
547
+ output_cfg_fpath = os.path.join(work_dir, eda_config.EDA_OUTPUT_CONFIG_FNAME)
548
+ data = yaml_safe_load(output_cfg_fpath)
548
549
  top = data.get('args', {}).get('top', '')
549
550
  if not top:
550
551
  self.error(f'"top" not found in synth run from {work_dir=} in',