opencos-eda 0.2.47__py3-none-any.whl → 0.2.49__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 (55) 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 +35 -18
  5. opencos/commands/sweep.py +9 -4
  6. opencos/commands/waves.py +1 -1
  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 +92 -67
  14. opencos/eda_base.py +625 -332
  15. opencos/eda_config.py +80 -14
  16. opencos/eda_extract_targets.py +22 -14
  17. opencos/eda_tool_helper.py +33 -7
  18. opencos/export_helper.py +166 -86
  19. opencos/export_json_convert.py +31 -23
  20. opencos/files.py +2 -1
  21. opencos/hw/__init__.py +0 -0
  22. opencos/{oc_cli.py → hw/oc_cli.py} +9 -4
  23. opencos/names.py +0 -4
  24. opencos/peakrdl_cleanup.py +13 -7
  25. opencos/seed.py +19 -11
  26. opencos/tests/helpers.py +27 -14
  27. opencos/tests/test_deps_helpers.py +35 -32
  28. opencos/tests/test_eda.py +47 -41
  29. opencos/tests/test_eda_elab.py +5 -3
  30. opencos/tests/test_eda_synth.py +1 -1
  31. opencos/tests/test_oc_cli.py +1 -1
  32. opencos/tests/test_tools.py +3 -2
  33. opencos/tools/iverilog.py +2 -2
  34. opencos/tools/modelsim_ase.py +2 -2
  35. opencos/tools/riviera.py +1 -1
  36. opencos/tools/slang.py +1 -1
  37. opencos/tools/surelog.py +1 -1
  38. opencos/tools/verilator.py +1 -1
  39. opencos/tools/vivado.py +1 -1
  40. opencos/tools/yosys.py +4 -3
  41. opencos/util.py +440 -483
  42. opencos/utils/__init__.py +0 -0
  43. opencos/utils/markup_helpers.py +98 -0
  44. opencos/utils/str_helpers.py +111 -0
  45. opencos/utils/subprocess_helpers.py +108 -0
  46. {opencos_eda-0.2.47.dist-info → opencos_eda-0.2.49.dist-info}/METADATA +1 -1
  47. opencos_eda-0.2.49.dist-info/RECORD +88 -0
  48. {opencos_eda-0.2.47.dist-info → opencos_eda-0.2.49.dist-info}/entry_points.txt +1 -1
  49. opencos/deps_helpers.py +0 -1346
  50. opencos_eda-0.2.47.dist-info/RECORD +0 -79
  51. /opencos/{pcie.py → hw/pcie.py} +0 -0
  52. {opencos_eda-0.2.47.dist-info → opencos_eda-0.2.49.dist-info}/WHEEL +0 -0
  53. {opencos_eda-0.2.47.dist-info → opencos_eda-0.2.49.dist-info}/licenses/LICENSE +0 -0
  54. {opencos_eda-0.2.47.dist-info → opencos_eda-0.2.49.dist-info}/licenses/LICENSE.spdx +0 -0
  55. {opencos_eda-0.2.47.dist-info → opencos_eda-0.2.49.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,26 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+ ''' peakrdl_cleanup is intended as CLI or callable via run(file-in, file-out)
4
+
5
+ to apply verilator comment waivers to a SystemVerilog file
6
+ '''
7
+
3
8
  import sys
4
- import os
5
9
 
6
- def run(file_in, file_out):
7
- with open(file_in) as f:
10
+
11
+ def run(file_in: str, file_out: str) -> None:
12
+ '''Returns None, writes file_out (filepath) with updates given file_in (filepath)'''
13
+
14
+ with open(file_in, encoding='utf-8') as f:
8
15
  lines = f.readlines()
9
16
 
10
- with open(file_out, 'w') as f:
17
+ with open(file_out, 'w', encoding='utf-8') as f:
11
18
  f.write('// verilator lint_off MULTIDRIVEN\n')
12
19
  for line in lines:
13
20
  f.write(line)
14
21
  f.write('// verilator lint_on MULTIDRIVEN\n')
15
22
 
23
+
16
24
  if __name__ == '__main__':
17
25
  assert len(sys.argv) == 3, f'{sys.argv=}'
18
- file_in = sys.argv[1]
19
- file_out = sys.argv[2]
20
- run(file_in, file_out)
26
+ run(file_in=sys.argv[1], file_out=sys.argv[2])
opencos/seed.py CHANGED
@@ -1,28 +1,36 @@
1
+ ''' opencos.seed handles getting a 'seed' int, and keeping a list of seeds.
2
+
3
+ Used by opencos.command.sim and opencos.tools, because some tools prefer 32-bit uint,
4
+ 31-bit > 0, or want to avoid a seed=0
5
+ '''
6
+
1
7
  import random
8
+ import time
2
9
 
3
- seeds = list()
10
+ seeds = []
4
11
 
12
+ def get_seed(style: str = "", limit_31bit: bool = True, avoid_zero: bool = True) -> int:
13
+ '''Returns a random int, using python random or time.time, with constraints.
5
14
 
6
- def get_seed(style : str = "", limit_31bit=True, avoid_zero=True):
7
- '''Returns a random int
15
+ Appends returned value to global list seeds.
8
16
 
9
17
  style (str)
10
- -- "", default: uses python random.randint
11
- -- "time" : uses python int(time.time())
18
+ -- "", default: uses python random.randint 32-bit
19
+ -- "time" : uses python time.time_ns() 32-bit LSBs
12
20
  '''
13
21
 
14
- global seeds
15
22
  seed = 1
16
23
 
17
24
  if style.lower() == "time":
18
- seed = int(time.time())
25
+ # use the float value fractional portion
26
+ seed = time.time_ns() & 0xFFFF_FFFF
19
27
  else:
20
- seed = random.randint(0, 0xFFFFFFFF)
28
+ seed = random.randint(0, 0xFFFF_FFFF)
21
29
 
22
- if limit_31bit and seed >> 31:
23
- seed >>= 1
30
+ if limit_31bit:
31
+ seed &= 0x7FFF_FFFF
24
32
  if avoid_zero and seed == 0:
25
- seed += 1
33
+ seed = 1
26
34
 
27
35
  seeds.append(seed)
28
36
  return seed
opencos/tests/helpers.py CHANGED
@@ -9,8 +9,9 @@ from pathlib import Path
9
9
 
10
10
  from contextlib import redirect_stdout, redirect_stderr
11
11
 
12
- from opencos import eda, util
12
+ from opencos import eda
13
13
  from opencos import deps_schema
14
+ from opencos.utils.markup_helpers import yaml_safe_load
14
15
 
15
16
  def can_run_eda_command(*commands, config: dict) -> bool:
16
17
  '''Returns True if we have any installed tool that can run: eda <command>'''
@@ -74,7 +75,7 @@ def assert_gen_deps_yml_good(filepath:str, want_target:str='') -> dict:
74
75
 
75
76
  so we also confirm they pass the deps_schema.FILE_SIMPLIFIED'''
76
77
  assert os.path.exists(filepath), f'{filepath=} does not exist'
77
- data = util.yaml_safe_load(filepath)
78
+ data = yaml_safe_load(filepath)
78
79
  assert len(data.keys()) > 0
79
80
  if want_target:
80
81
  assert want_target, f'{want_target=} not in {filepath=} {data=}'
@@ -124,20 +125,35 @@ def assert_export_jsonl_good(filepath:str, jsonl:bool=True) -> list:
124
125
  class Helpers:
125
126
  '''We do so much with logging in this file, might as well make it reusable'''
126
127
  DEFAULT_DIR = ''
127
- DEFAULT_LOG = 'eda.log'
128
+ DEFAULT_LOG_DIR = os.getcwd()
129
+ DEFAULT_LOG = os.path.join(DEFAULT_LOG_DIR, '.pytest.eda.log')
128
130
  def chdir(self):
129
131
  '''Changes directory to self.DEFAULT_DIR and removes eda.work, eda.export paths'''
130
132
  chdir_remove_work_dir('', self.DEFAULT_DIR)
131
133
 
134
+ def _resolve_logfile(self, logfile=None) -> str:
135
+ '''Returns the logfile's filepath'''
136
+ ret = logfile
137
+ if ret is None:
138
+ ret = self.DEFAULT_LOG
139
+ else:
140
+ left, right = os.path.split(logfile)
141
+ if not left or left in [os.path.sep, '.', '..']:
142
+ # relative logfile put in DEFAULT_LOG_DIR:
143
+ ret = os.path.join(self.DEFAULT_LOG_DIR, right)
144
+ return ret
145
+
132
146
  def log_it(self, command_str:str, logfile=None, use_eda_wrap=True) -> int:
133
147
  '''Replacement for calling eda.main or eda_wrap, when you want an internal logfile
134
148
 
135
149
  Usage:
136
- rc = self.log_it('sim foo', logfile='yes.log')
150
+ rc = self.log_it('sim foo')
137
151
  assert rc == 0
152
+
153
+ Note this will run with --no-default-log to avoid a Windows problem with stomping
154
+ on a log file.
138
155
  '''
139
- if logfile is None:
140
- logfile = self.DEFAULT_LOG
156
+ logfile = self._resolve_logfile(logfile)
141
157
  rc = 50
142
158
 
143
159
  # TODO(drew): There are some issues with log_it redirecting stdout from vivado
@@ -148,16 +164,15 @@ class Helpers:
148
164
  with open(logfile, 'w', encoding='utf-8') as f:
149
165
  with redirect_stdout(f), redirect_stderr(f):
150
166
  if use_eda_wrap:
151
- rc = eda_wrap(*(command_str.split()))
167
+ rc = eda_wrap('--no-default-log', *(command_str.split()))
152
168
  else:
153
- rc = eda.main(*(command_str.split()))
169
+ rc = eda.main('--no-default-log', *(command_str.split()))
154
170
  print(f'Wrote: {os.path.abspath(logfile)=}')
155
171
  return rc
156
172
 
157
173
  def is_in_log(self, *want_str, logfile=None, windows_path_support=False):
158
174
  '''Check if any of want_str args are in the logfile, or self.DEFAULT_LOG'''
159
- if logfile is None:
160
- logfile = self.DEFAULT_LOG
175
+ logfile = self._resolve_logfile(logfile)
161
176
  want_str0 = ' '.join(list(want_str))
162
177
  want_str1 = want_str0.replace('/', '\\')
163
178
  with open(logfile, encoding='utf-8') as f:
@@ -169,8 +184,7 @@ class Helpers:
169
184
 
170
185
  def get_log_lines_with(self, *want_str, logfile=None, windows_path_support=False):
171
186
  '''gets all log lines with any of want_str args are in the logfile, or self.DEFAULT_LOG'''
172
- if logfile is None:
173
- logfile = self.DEFAULT_LOG
187
+ logfile = self._resolve_logfile(logfile)
174
188
  ret_list = []
175
189
  want_str0 = ' '.join(list(want_str))
176
190
  want_str1 = want_str0.replace('/', '\\')
@@ -186,8 +200,7 @@ class Helpers:
186
200
  '''gets all log lines with any of *want_str within a single word
187
201
  in the logfile or self.DEFAULT_LOG
188
202
  '''
189
- if logfile is None:
190
- logfile = self.DEFAULT_LOG
203
+ logfile = self._resolve_logfile(logfile)
191
204
  ret_list = []
192
205
  want_str0 = ' '.join(list(want_str))
193
206
  want_str1 = want_str0.replace('/', '\\')
@@ -1,7 +1,7 @@
1
- '''pytests for opencos.deps_helpers'''
1
+ '''pytests for opencos.deps modules'''
2
2
 
3
- # TODO(drew): these need to be refactored if we cleanup deps_helpers.py, this still
4
- # uses the old DEPS (non-markup) command format, such as 'shell@some bash command'
3
+ # TODO(drew): these need to be refactored if we cleanup opencos.deps commands;
4
+ # this uses the old DEPS (non-markup) command format, such as 'shell@some bash command'
5
5
 
6
6
  # TODO(drew): for now, ignore long lines and docstrings
7
7
  # pylint: disable=line-too-long,missing-function-docstring
@@ -10,7 +10,9 @@ from pathlib import Path
10
10
  import os
11
11
  import pytest
12
12
 
13
- from opencos import eda_tool_helper, deps_helpers
13
+ from opencos import eda_tool_helper
14
+
15
+ from opencos.deps import deps_file, deps_commands
14
16
 
15
17
  THISPATH = os.path.dirname(__file__)
16
18
 
@@ -19,9 +21,9 @@ config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
19
21
 
20
22
 
21
23
  def test_get_all_targets():
22
- '''Makes sure that deps_helpers.get_all_targets(filter_str:str) works'''
24
+ '''Makes sure that deps_file.get_all_targets(filter_str:str) works'''
23
25
 
24
- targets = deps_helpers.get_all_targets(
26
+ targets = deps_file.get_all_targets(
25
27
  dirs=[
26
28
  str(Path('../../lib/tests')),
27
29
  str(Path('../../lib/rams/tests')),
@@ -42,9 +44,9 @@ def test_get_all_targets():
42
44
  reason="requires vivado or verilator"
43
45
  )
44
46
  def test_get_all_targets_eda_multi():
45
- '''Makes sure that deps_helpers.get_all_targets(filter_using_mult:str) works'''
47
+ '''Makes sure that deps_file.get_all_targets(filter_using_mult:str) works'''
46
48
 
47
- targets = deps_helpers.get_all_targets(
49
+ targets = deps_file.get_all_targets(
48
50
  base_path=THISPATH,
49
51
  filter_using_multi='sim ../../lib/tests/*test ../../lib/rams/tests/*test',
50
52
  )
@@ -57,26 +59,26 @@ def test_get_all_targets_eda_multi():
57
59
 
58
60
  def test_parse_deps_shell_str__no_parse():
59
61
  line = 'some_file.sv'
60
- d = deps_helpers.parse_deps_shell_str(line, '', '')
62
+ d = deps_commands.parse_deps_shell_str(line, '', '')
61
63
  assert not d, f'{d=}'
62
64
 
63
65
  line = 'some_target:'
64
- d = deps_helpers.parse_deps_shell_str(line, '', '')
66
+ d = deps_commands.parse_deps_shell_str(line, '', '')
65
67
  assert not d, f'{d=}'
66
68
 
67
69
  line = ' csr@some_file.sv'
68
- d = deps_helpers.parse_deps_shell_str(line, '', '')
70
+ d = deps_commands.parse_deps_shell_str(line, '', '')
69
71
  assert not d, f'{d=}'
70
72
 
71
73
  def test_parse_deps_shell_str__cp():
72
74
  line = ' shell@ cp ./oclib_fifo_test.sv oclib_fifo_test_COPY.sv ;'
73
- d = deps_helpers.parse_deps_shell_str(line, '', '')
75
+ d = deps_commands.parse_deps_shell_str(line, '', '')
74
76
  assert d, f'{d=}'
75
77
  assert d['exec_list'] == ['cp', './oclib_fifo_test.sv', 'oclib_fifo_test_COPY.sv', ';'], f'{d=}'
76
78
 
77
79
  def test_parse_deps_shell_str__echo():
78
80
  line = ' shell@echo "hello world"'
79
- d = deps_helpers.parse_deps_shell_str(line, '', '')
81
+ d = deps_commands.parse_deps_shell_str(line, '', '')
80
82
  assert d, f'{d=}'
81
83
  assert d['exec_list'] == ['echo', '"hello', 'world"'], f'{d=}'
82
84
 
@@ -85,10 +87,11 @@ def test_parse_deps_shell_str__enable_filepath_replacement():
85
87
  # Default is enabled.
86
88
  module_dir = os.path.dirname(os.path.abspath(__file__))
87
89
  os.chdir(module_dir)
88
- line = 'shell@cp ../deps_helpers.py foo.py'
89
- d = deps_helpers.parse_deps_shell_str(line, target_path='./', target_node='foo_target')
90
+ line = 'shell@cp ../deps/deps_commands.py .pytest.copied.py'
91
+ d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target')
90
92
  assert d, f'{d=}'
91
- assert d['exec_list'] == ['cp', os.path.abspath('../deps_helpers.py'), 'foo.py'], f'{d=}'
93
+ spath = os.path.abspath(os.path.join('..', 'deps', 'deps_commands.py'))
94
+ assert d['exec_list'] == ['cp', spath, '.pytest.copied.py'], f'{d=}'
92
95
  assert d['target_node'] == 'foo_target'
93
96
  assert d['target_path'] == os.path.abspath('./')
94
97
 
@@ -96,11 +99,11 @@ def test_parse_deps_shell_str__disable_filepath_replacement():
96
99
  # Dealing w/ relative paths, change the current working directory to the module directory
97
100
  module_dir = os.path.dirname(os.path.abspath(__file__))
98
101
  os.chdir(module_dir)
99
- line = 'shell@cp ../deps_helpers.py foo.py'
100
- d = deps_helpers.parse_deps_shell_str(line, target_path='./', target_node='foo_target',
102
+ line = 'shell@cp ../deps/deps_commands.py .pytest.copied.py'
103
+ d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target',
101
104
  enable_filepath_subst_target_dir=False)
102
105
  assert d, f'{d=}'
103
- assert d['exec_list'] == ['cp', '../deps_helpers.py', 'foo.py'], f'{d=}'
106
+ assert d['exec_list'] == ['cp', '../deps/deps_commands.py', '.pytest.copied.py'], f'{d=}'
104
107
  assert d['target_node'] == 'foo_target'
105
108
  assert d['target_path'] == os.path.abspath('./')
106
109
 
@@ -109,7 +112,7 @@ def test_parse_deps_shell_str__enable_dirpath_replacement():
109
112
  module_dir = os.path.dirname(os.path.abspath(__file__))
110
113
  os.chdir(module_dir)
111
114
  line = 'shell@ls -ltr ./'
112
- d = deps_helpers.parse_deps_shell_str(line, target_path='./', target_node='foo_target',
115
+ d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target',
113
116
  enable_dirpath_subst_target_dir=True)
114
117
  assert d, f'{d=}'
115
118
  assert d['exec_list'] == ['ls', '-ltr', os.path.abspath('./')], f'{d=}'
@@ -122,7 +125,7 @@ def test_parse_deps_shell_str__disable_dirpath_replacement():
122
125
  module_dir = os.path.dirname(os.path.abspath(__file__))
123
126
  os.chdir(module_dir)
124
127
  line = 'shell@ls -ltr ./'
125
- d = deps_helpers.parse_deps_shell_str(line, target_path='./', target_node='foo_target')
128
+ d = deps_commands.parse_deps_shell_str(line, target_path='./', target_node='foo_target')
126
129
  assert d, f'{d=}'
127
130
  assert d['exec_list'] == ['ls', '-ltr', './'], f'{d=}'
128
131
  assert d['target_node'] == 'foo_target'
@@ -131,26 +134,26 @@ def test_parse_deps_shell_str__disable_dirpath_replacement():
131
134
 
132
135
  def test_parse_deps_work_dir_add_srcs__no_parse():
133
136
  line = 'some_file.sv'
134
- d = deps_helpers.parse_deps_work_dir_add_srcs(line, '', '')
137
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
135
138
  assert not d, f'{d=}'
136
139
 
137
140
  line = 'some_target:'
138
- d = deps_helpers.parse_deps_work_dir_add_srcs(line, '', '')
141
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
139
142
  assert not d, f'{d=}'
140
143
 
141
144
  line = ' csr@some_file.sv'
142
- d = deps_helpers.parse_deps_work_dir_add_srcs(line, '', '')
145
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
143
146
  assert not d, f'{d=}'
144
147
 
145
148
  def test_parse_deps_work_dir_add_srcs__single_file():
146
149
  line = ' work_dir_add_srcs@ single_file.txt'
147
- d = deps_helpers.parse_deps_work_dir_add_srcs(line, '', '')
150
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
148
151
  assert d, f'{d=}'
149
152
  assert d['file_list'] == ['single_file.txt']
150
153
 
151
154
  def test_parse_deps_work_dir_add_srcs__several_file():
152
155
  line = ' work_dir_add_srcs@ single_file.txt another.sv gen-verilog/mine.v ./gen-vhdl/wordy.vhdl'
153
- d = deps_helpers.parse_deps_work_dir_add_srcs(line, '', '')
156
+ d = deps_commands.parse_deps_work_dir_add_srcs(line, '', '')
154
157
  assert d, f'{d=}'
155
158
  assert d['file_list'] == [
156
159
  'single_file.txt', 'another.sv', 'gen-verilog/mine.v', './gen-vhdl/wordy.vhdl'
@@ -159,34 +162,34 @@ def test_parse_deps_work_dir_add_srcs__several_file():
159
162
 
160
163
  def test_parse_deps_peakrdl__no_parse():
161
164
  line = 'some_file.sv'
162
- d = deps_helpers.parse_deps_peakrdl(line, '', '')
165
+ d = deps_commands.parse_deps_peakrdl(line, '', '')
163
166
  assert not d, f'{d=}'
164
167
 
165
168
  line = 'some_target:'
166
- d = deps_helpers.parse_deps_peakrdl(line, '', '')
169
+ d = deps_commands.parse_deps_peakrdl(line, '', '')
167
170
  assert not d, f'{d=}'
168
171
 
169
172
  line = ' csr@some_file.sv'
170
- d = deps_helpers.parse_deps_peakrdl(line, '', '')
173
+ d = deps_commands.parse_deps_peakrdl(line, '', '')
171
174
  assert not d, f'{d=}'
172
175
 
173
176
  def test_parse_deps_peakrdl__with_top():
174
177
  line = ' peakrdl@ --cpuif axi4-lite-flat --top my_fancy_csrs ./my_csrs.rdl'
175
- d = deps_helpers.parse_deps_peakrdl(line, '', '')
178
+ d = deps_commands.parse_deps_peakrdl(line, '', '')
176
179
  assert d, f'{d=}'
177
180
  assert len(d['shell_commands_list']) > 0
178
181
  assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_fancy_csrs_pkg.sv', 'peakrdl/my_fancy_csrs.sv']
179
182
 
180
183
  def test_parse_deps_peakrdl__with_top2():
181
184
  line = ' peakrdl@ --cpuif axi4-lite-flat --top=my_fancy_csrs ./my_csrs.rdl'
182
- d = deps_helpers.parse_deps_peakrdl(line, '', '')
185
+ d = deps_commands.parse_deps_peakrdl(line, '', '')
183
186
  assert d, f'{d=}'
184
187
  assert len(d['shell_commands_list']) > 0
185
188
  assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_fancy_csrs_pkg.sv', 'peakrdl/my_fancy_csrs.sv']
186
189
 
187
190
  def test_parse_deps_peakrdl__infer_top():
188
191
  line = ' peakrdl@ --cpuif axi4-lite-flat ./my_csrs.rdl'
189
- d = deps_helpers.parse_deps_peakrdl(line, '', '')
192
+ d = deps_commands.parse_deps_peakrdl(line, '', '')
190
193
  assert d, f'{d=}'
191
194
  assert len(d['shell_commands_list']) > 0
192
195
  assert d['work_dir_add_srcs']['file_list'] == ['peakrdl/my_csrs_pkg.sv', 'peakrdl/my_csrs.sv']