opencos-eda 0.2.36__py3-none-any.whl → 0.2.39__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.
@@ -3,6 +3,28 @@
3
3
  # python mergedeep with Strategy.TYPESAFE_REPLACE. I considered doing TYPESAFE_ADDITIVE but then
4
4
  # the user would lose full control over existing list values.
5
5
 
6
+ DEFAULT_HANDLERS:
7
+ # These commands (sim, elab, etc) require a tool, but have a default handler
8
+ # base class:
9
+ sim : opencos.commands.CommandSim
10
+ elab : opencos.commands.CommandElab
11
+ synth : opencos.commands.CommandSynth
12
+ flist : opencos.commands.CommandFList
13
+ proj : opencos.commands.CommandProj
14
+ build : opencos.commands.CommandBuild
15
+ upload : opencos.commands.CommandUpload
16
+ open : opencos.commands.CommandOpen
17
+ # These commands don't necessarily require a tool
18
+ multi : opencos.commands.CommandMulti
19
+ tools-multi : opencos.commands.CommandToolsMulti
20
+ sweep : opencos.commands.CommandSweep
21
+ # These commands (waves, export, targets) do not require a tool, or
22
+ # will self determine the tool:
23
+ waves : opencos.commands.CommandWaves
24
+ export : opencos.commands.CommandExport
25
+ targets : opencos.commands.CommandTargets
26
+
27
+
6
28
  defines: { } # Add these defines to every eda call
7
29
 
8
30
  dep_command_enables:
@@ -47,9 +69,14 @@ file_extensions:
47
69
  - .vhdl
48
70
 
49
71
  command_determines_tool:
50
- # eda commands that will self-determine the tool to use.
72
+ # eda commands that will self-determine the tool to use
51
73
  - waves
52
74
 
75
+ command_uses_no_tools:
76
+ # eda commands that do not use a tool at all, will skip auto_tools_order
77
+ - export
78
+ - targets
79
+
53
80
 
54
81
  tools:
55
82
 
@@ -9,7 +9,6 @@ dep_command_enables:
9
9
  var_subst_os_env: false
10
10
 
11
11
  # Values overriden to false:
12
- deps_legacy_supported: false
13
12
  deps_subprocess_shell: false
14
13
 
15
14
 
@@ -35,7 +35,7 @@ _eda_script_completion() {
35
35
  if [ -z "${completions}" ]; then
36
36
  # If we didn't find anything in a DEPS.[yml|yaml|toml|json], then use:
37
37
  # 1. a bunch of known eda words or args.
38
- eda_words="multi sim elab flist build synth waves proj waves \
38
+ eda_words="multi sim elab flist build synth waves proj waves targets \
39
39
  +define+ +incdirs+ \
40
40
  --help --quiet --verbose --debug \
41
41
  --tool --seed --top --keep --force --fake --lint --work-dir \
@@ -72,12 +72,8 @@ def print_columns_manual(data: list, num_columns: int = 4, auto_columns: bool =
72
72
  if col_index == num_columns - 1 or i == len(data) - 1:
73
73
  print() # New line at the end of a row or end of data
74
74
 
75
-
76
- def run(partial_path: str = '', base_path=str(Path('.'))) -> None:
77
- '''Returns None, prints DEPS keys into pretty columns, using arg
78
-
79
- partial_path as a string filter for target completions.
80
- '''
75
+ def get_path_and_pattern(partial_path: str = '', base_path=str(Path('.'))) -> (str, str):
76
+ '''Returns tuple of (partial_path, partial_target or filter)'''
81
77
  partial_target = ''
82
78
  if not partial_path or partial_path == str(Path('.')):
83
79
  partial_path = PATH_LPREFIX
@@ -86,18 +82,40 @@ def run(partial_path: str = '', base_path=str(Path('.'))) -> None:
86
82
  if not partial_path:
87
83
  partial_path = PATH_LPREFIX
88
84
 
89
- try:
90
- keys = get_all_targets(
91
- dirs=[partial_path],
92
- base_path=base_path,
93
- filter_str=partial_target,
94
- error_on_empty_return=False,
95
- lstrip_path=True
96
- )
97
- except:
98
- keys = []
85
+ return partial_path, partial_target
99
86
 
100
- print_columns_manual(data=keys, num_columns=4, auto_columns=True)
87
+
88
+
89
+ def run(partial_paths: list, base_path=str(Path('.'))) -> None:
90
+ '''Returns None, prints DEPS keys into pretty columns, using arg
91
+
92
+ partial_path as a string filter for target completions.
93
+ '''
94
+
95
+ targets_set = set()
96
+ if not partial_paths:
97
+ partial_paths = [PATH_LPREFIX] # run on current directory.
98
+
99
+ for partial_path in partial_paths:
100
+ partial_path, partial_target = get_path_and_pattern(
101
+ partial_path=partial_path, base_path=base_path
102
+ )
103
+ try:
104
+ keys = get_all_targets(
105
+ dirs=[partial_path],
106
+ base_path=base_path,
107
+ filter_str=partial_target,
108
+ error_on_empty_return=False,
109
+ lstrip_path=True
110
+ )
111
+ except:
112
+ keys = []
113
+ for key in keys:
114
+ targets_set.add(key)
115
+
116
+ data = list(targets_set)
117
+ data.sort()
118
+ print_columns_manual(data=data, num_columns=4, auto_columns=True)
101
119
 
102
120
 
103
121
  def main() -> None:
@@ -109,8 +127,8 @@ def main() -> None:
109
127
  if len(sys.argv) > 1:
110
128
  partial_path = sys.argv[1]
111
129
  else:
112
- partial_path = PATH_LPREFIX
113
- run(partial_path)
130
+ partial_path = ''
131
+ run(partial_paths=[partial_path])
114
132
 
115
133
 
116
134
  if __name__ == "__main__":
opencos/files.py CHANGED
@@ -29,7 +29,7 @@ ALL_FORCED_PREFIXES = set(list(FORCE_PREFIX_DICT.keys()))
29
29
 
30
30
  def get_source_file(target:str) -> (bool, str, str):
31
31
  '''Returns tuple: bool if file exists, filepath str, and optional forced file type str'''
32
- if os.path.exists(target):
32
+ if os.path.isfile(target):
33
33
  # target exists as a file, return True w/ original target:
34
34
  return True, target, ''
35
35
 
@@ -37,7 +37,7 @@ def get_source_file(target:str) -> (bool, str, str):
37
37
  for p in ALL_FORCED_PREFIXES:
38
38
  if p in target:
39
39
  fpath = ''.join(target.split(p)) # essentially just removing the "sv@" or whatever it is
40
- if os.path.exists(fpath):
40
+ if os.path.isfile(fpath):
41
41
  return True, fpath, FORCE_PREFIX_DICT.get(p)
42
42
 
43
43
  # target or fpath didn't exist, return False with the original target:
opencos/tests/helpers.py CHANGED
@@ -142,13 +142,14 @@ class Helpers:
142
142
  # TODO(drew): There are some issues with log_it redirecting stdout from vivado
143
143
  # and modelsim_ase. So this may not work for all tools, you may have to directly
144
144
  # look at eda.work/{target}.sim/sim.log or xsim.log.
145
+ print(f'{os.getcwd()=}')
146
+ print(f'{command_str=}')
145
147
  with open(logfile, 'w', encoding='utf-8') as f:
146
- with redirect_stdout(f):
147
- with redirect_stderr(f):
148
- if use_eda_wrap:
149
- rc = eda_wrap(*(command_str.split()))
150
- else:
151
- rc = eda.main(*(command_str.split()))
148
+ with redirect_stdout(f), redirect_stderr(f):
149
+ if use_eda_wrap:
150
+ rc = eda_wrap(*(command_str.split()))
151
+ else:
152
+ rc = eda.main(*(command_str.split()))
152
153
  print(f'Wrote: {os.path.abspath(logfile)=}')
153
154
  return rc
154
155
 
opencos/tests/test_eda.py CHANGED
@@ -53,6 +53,28 @@ def test_args_sim_default_tool():
53
53
  assert rc == 0
54
54
 
55
55
 
56
+ class TestTargets(Helpers):
57
+ '''Tests for: eda targets'''
58
+
59
+ DEFAULT_DIR = os.path.join(THISPATH, '..', '..', 'lib', 'tests')
60
+
61
+ def test_lib_tests__no_pattern(self):
62
+ '''Test that this works: eda targets'''
63
+ self.chdir()
64
+ rc = self.log_it('targets --debug', use_eda_wrap=False)
65
+ assert rc == 0
66
+ assert self.is_in_log('oclib_fifo_test')
67
+ assert self.is_in_log('oclib_rrarb_test')
68
+
69
+ def test_lib_tests__with_pattern(self):
70
+ '''Test that this works: eda targets oclib_fifo*test'''
71
+ self.chdir()
72
+ rc = self.log_it('targets oclib_fifo*test', use_eda_wrap=False)
73
+ assert rc == 0
74
+ assert self.is_in_log('oclib_fifo_test')
75
+ assert not self.is_in_log('oclib_rrarb_test')
76
+
77
+
56
78
  @pytest.mark.skipif(
57
79
  'verilator' not in tools_loaded, reason="requires verilator"
58
80
  )
opencos/tools/invio.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  # pylint: disable=R0801 # (duplicate code in derived classes, such as if-condition return.)
4
4
 
5
- import shutil
6
5
  import importlib.util
7
6
 
8
7
  from opencos import util
@@ -22,11 +21,11 @@ class ToolInvio(Tool):
22
21
  if self._VERSION:
23
22
  return self._VERSION
24
23
 
25
- # We also have to make sure invio-py exists, or that we can import invio within python.
26
- invio_py_path = shutil.which('invio-py')
24
+ # We also have to make sure we can import invio within python.
27
25
  spec = importlib.util.find_spec('invio')
28
- if not spec or not invio_py_path:
29
- self.error('"invio-py" not in path, or invio package not in python env')
26
+ if not spec:
27
+ self.error('"invio" package not in python env')
28
+
30
29
 
31
30
  return super().get_versions()
32
31
 
@@ -5,7 +5,6 @@
5
5
  # pylint: disable=too-many-locals # TODO(drew): fix this later.
6
6
 
7
7
  import os
8
- import shutil
9
8
  import importlib.util
10
9
 
11
10
  from opencos import util
@@ -23,11 +22,10 @@ class ToolInvioYosys(ToolYosys):
23
22
  if self._VERSION:
24
23
  return self._VERSION
25
24
 
26
- # We also have to make sure invio-py exists, or that we can import invio within python.
27
- invio_py_path = shutil.which('invio-py')
25
+ # We also have to make sure we can import invio within python.
28
26
  spec = importlib.util.find_spec('invio')
29
- if not spec or not invio_py_path:
30
- self.error('"invio-py" not in path, or invio package not in python env')
27
+ if not spec:
28
+ self.error('"invio" package not in python env')
31
29
 
32
30
  # run ToolYosys.get_versions() to set up self.yosys_exe, and return the version
33
31
  # str:
@@ -49,6 +47,9 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
49
47
  self.args.update({
50
48
  'invio-blackbox': [], # list of modules that invio/verific will blackbox.
51
49
  })
50
+ self.args_help.update({
51
+ 'invio-blackbox': 'List of modules that invio will blackbox prior to yosys',
52
+ })
52
53
 
53
54
  def write_and_run_yosys_f_files(self, **kwargs) -> None:
54
55
 
@@ -74,13 +75,13 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
74
75
  os.mkdir(fullp)
75
76
 
76
77
  # create yosys.f so we can run a few commands within yosys.
77
- yosys_f_path = os.path.join(work_dir, 'yosys.f')
78
- yosys_v_path = os.path.join(work_dir, 'yosys', invio_dict['v_filename'])
79
-
80
- synth_command = self.args.get('yosys-synth', 'synth')
78
+ yosys_f_path = os.path.join(self.full_work_dir, 'yosys.f')
79
+ self.yosys_v_path = os.path.join(self.yosys_out_dir, invio_dict['v_filename'])
81
80
 
82
81
  with open(yosys_f_path, 'w', encoding='utf-8') as f:
83
82
  lines = []
83
+ if self.args['liberty-file']:
84
+ lines.append('read_liberty -lib ' + self.args['liberty-file'])
84
85
  for path in invio_dict.get('blackbox_files_list', []):
85
86
  # We have to read the verilog files from the invio blackbox_files_list:
86
87
  lines.append(f'read_verilog {path}')
@@ -88,12 +89,9 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
88
89
  # But we may blackbox different cells for yosys synthesis.
89
90
  lines.append(f'blackbox {module}')
90
91
 
92
+
91
93
  lines.append(f'read_verilog {invio_dict["full_v_filename"]}')
92
- lines += self.args.get('yosys-pre-synth', [])
93
- lines += [
94
- synth_command,
95
- f'write_verilog {yosys_v_path}'
96
- ]
94
+ lines += self.get_synth_command_lines()
97
95
  f.write('\n'.join(lines))
98
96
 
99
97
  synth_command_list = util.ShellCommandList(
@@ -105,6 +103,9 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
105
103
  ['python3', invio_dict['full_py_filename']], tee_fpath=invio_dict['full_py_filename']
106
104
  )
107
105
 
106
+ # Optinally create and run a sta.f:
107
+ sta_command_list = self.create_sta_f() # [] or util.ShellCommandList
108
+
108
109
  # We create a run_yosys.sh wrapping these scripts, but we do not run this one.
109
110
  util.write_shell_command_file(
110
111
  dirpath=self.args['work-dir'],
@@ -121,18 +122,25 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
121
122
  # Gives us bash commands with tee and pipstatus:
122
123
  invio_command_list,
123
124
  synth_command_list,
125
+ sta_command_list,
124
126
  ],
125
127
  )
126
128
 
127
129
  # Do not run this if args['stop-before-compile'] is True
128
130
  if self.args.get('stop-before-compile', False) or \
129
131
  self.args.get('stop-after-compile', False):
130
- pass # skip it.
131
- else:
132
- self.exec( work_dir=work_dir, command_list=synth_command_list,
133
- tee_fpath=synth_command_list.tee_fpath )
134
- util.info(f'yosys: wrote verilog to {yosys_v_path}')
135
- return self.status
132
+ return
133
+
134
+ # Run the synth commands standalone:
135
+ self.exec( work_dir=work_dir, command_list=synth_command_list,
136
+ tee_fpath=synth_command_list.tee_fpath )
137
+
138
+ if self.args['sta']:
139
+ self.exec(work_dir=self.full_work_dir, command_list=sta_command_list,
140
+ tee_fpath=sta_command_list.tee_fpath)
141
+
142
+ if self.status == 0:
143
+ util.info(f'yosys: wrote verilog to {self.yosys_v_path}')
136
144
 
137
145
 
138
146
  class CommandElabInvioYosys(CommandSynthInvioYosys):
opencos/tools/iverilog.py CHANGED
@@ -156,8 +156,10 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
156
156
  # +define+{k}={v}, but also for SystemVerilog plusargs
157
157
  command_list += [ '-D', f'{k}={sanitize_defines_for_sh(v)}' ]
158
158
 
159
- assert len(self.files_sv) + len(self.files_v) > 0, \
160
- f'{self.target=} {self.files_sv=} and {self.files_v=} are empty, cannot call iverilog'
159
+ if not self.files_sv and not self.files_v:
160
+ if not self.args['stop-before-compile']:
161
+ self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
162
+ 'cannot call iverilog')
161
163
 
162
164
  command_list += list(self.files_sv) + list(self.files_v)
163
165
 
@@ -178,9 +178,10 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
178
178
  '-source',
179
179
  ] + list(self.files_sv) + list(self.files_v)
180
180
 
181
- if len(self.files_sv) + len(self.files_v) == 0:
182
- self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
183
- 'cannot create a valid vlog.f')
181
+ if not self.files_sv and not self.files_v:
182
+ if not self.args['stop-before-compile']:
183
+ self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
184
+ 'cannot create a valid vlog.f')
184
185
 
185
186
  with open(vlog_dot_f_fpath, 'w', encoding='utf-8') as f:
186
187
  f.writelines(line + "\n" for line in vlog_dot_f_lines)
@@ -8,8 +8,7 @@ Contains classes for ToolSlangYosys, CommandSynthSlangYosys
8
8
  import os
9
9
 
10
10
  from opencos import util
11
- from opencos.commands import CommandSynth
12
- from opencos.tools.yosys import ToolYosys
11
+ from opencos.tools.yosys import ToolYosys, CommonSynthYosys
13
12
 
14
13
  class ToolSlangYosys(ToolYosys):
15
14
  '''Uses slang.so in yosys plugins directory, called via yosys > plugin -i slang'''
@@ -28,49 +27,17 @@ class ToolSlangYosys(ToolYosys):
28
27
  })
29
28
 
30
29
 
31
- class CommandSynthSlangYosys(CommandSynth, ToolSlangYosys):
30
+ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
32
31
  '''CommandSynthSlangYosys is a command handler for: eda synth --tool=slang_yosys'''
33
32
 
34
33
  def __init__(self, config: dict):
35
- CommandSynth.__init__(self, config)
34
+ CommonSynthYosys.__init__(self, config)
36
35
  ToolSlangYosys.__init__(self, config=self.config)
37
- self.args.update({
38
- 'sta': False,
39
- 'liberty-file': '',
40
- 'sdc-file': '',
41
- 'yosys-synth': 'synth', # synth_xilinx, synth_altera, etc (see: yosys help)
42
- 'yosys-pre-synth': ['prep', 'proc'], # command run in yosys prior to yosys-synth.
43
- 'yosys-blackbox': [], # list of modules that yosys will blackbox.
44
- })
45
- self.args_help.update({
46
- 'sta': 'After running Yosys, run "sta" with --liberty-file.' \
47
- + ' sta can be installed via: https://github.com/The-OpenROAD-Project/OpenSTA',
48
- 'sdc-file': '.sdc file to use with --sta, if not present will use auto constraints',
49
- 'liberty-file': 'Single liberty file for synthesis and sta,' \
50
- + ' for example: github/OpenSTA/examples/nangate45_slow.lib.gz',
51
- 'yosys-synth': 'The synth command provided to Yosys, see: yosys help.',
52
- 'yosys-pre-synth': 'Yosys commands performed prior to running "synth"' \
53
- + ' (or eda arg value for --yosys-synth)',
54
- 'yosys-blackbox': 'List of modules that yosys will blackbox, likely will need these' \
55
- + ' in Verilog-2001 for yosys to read outside of slang and synth',
56
- })
57
36
 
58
37
  self.slang_out_dir = ''
59
- self.yosys_out_dir = ''
60
38
  self.slang_v_path = ''
61
- self.yosys_v_path = ''
62
- self.full_work_dir = ''
63
- self.blackbox_list = []
64
39
 
65
- def do_it(self) -> None:
66
- CommandSynth.do_it(self)
67
-
68
- if self.is_export_enabled():
69
- return
70
-
71
- self._write_and_run_yosys_f_files()
72
-
73
- def _write_and_run_yosys_f_files(self):
40
+ def write_and_run_yosys_f_files(self, **kwargs) -> None:
74
41
  '''
75
42
  1. Creates and runs: yosys.slang.f
76
43
  -- should create post_slang_ls.txt
@@ -88,28 +55,20 @@ class CommandSynthSlangYosys(CommandSynth, ToolSlangYosys):
88
55
  util.debug(f'slang_yosys: {self.blackbox_list=}')
89
56
 
90
57
  # create {work_dir} / yosys
91
- self.full_work_dir = self.args.get('work-dir', '')
92
- if not self.full_work_dir:
93
- self.error(f'work_dir={self.full_work_dir} is not set')
94
- self.full_work_dir = os.path.abspath(self.full_work_dir)
95
58
  self.slang_out_dir = os.path.join(self.full_work_dir, 'slang')
96
- self.yosys_out_dir = os.path.join(self.full_work_dir, 'yosys')
97
- for p in [self.slang_out_dir, self.yosys_out_dir]:
98
- util.safe_mkdir(p)
59
+ util.safe_mkdir(self.slang_out_dir)
99
60
 
100
61
  self.slang_v_path = os.path.join(self.slang_out_dir, f'{self.args["top"]}.v')
101
- self.yosys_v_path = os.path.join(self.yosys_out_dir, f'{self.args["top"]}.v')
102
-
103
62
 
104
63
  # Run our created yosys.slang.f script
105
64
  # Note - this will always run, even if --stop-before-compile is set.
106
65
  slang_command_list = self._create_yosys_slang_f() # util.ShellCommandList
107
66
 
108
67
  # Create and run yosys.synth.f
109
- synth_command_list = self._create_yosys_synth_f() # util.ShellCommandList
68
+ synth_command_list = self.create_yosys_synth_f() # util.ShellCommandList
110
69
 
111
70
  # Optinally create and run a sta.f:
112
- sta_command_list = self._create_sta_f() # [] or util.ShellCommandList
71
+ sta_command_list = self.create_sta_f() # [] or util.ShellCommandList
113
72
 
114
73
  # We create a run_yosys.sh wrapping these scripts, but we do not run this one.
115
74
  util.write_shell_command_file(
@@ -246,7 +205,7 @@ class CommandSynthSlangYosys(CommandSynth, ToolSlangYosys):
246
205
  yosys_blackbox_list.append(line)
247
206
  return yosys_blackbox_list
248
207
 
249
- def _create_yosys_synth_f(self) -> util.ShellCommandList:
208
+ def create_yosys_synth_f(self) -> util.ShellCommandList:
250
209
  # Create yosys.synth.f
251
210
  yosys_synth_f_path = os.path.join(self.full_work_dir, 'yosys.synth.f')
252
211
 
@@ -254,10 +213,6 @@ class CommandSynthSlangYosys(CommandSynth, ToolSlangYosys):
254
213
  # yosys.synth.f script.
255
214
  yosys_blackbox_list = self._get_yosys_blackbox_list()
256
215
 
257
- synth_command = self.args.get('yosys-synth', 'synth')
258
- if self.args['flatten-all']:
259
- synth_command += ' -flatten'
260
-
261
216
  if self.args['liberty-file'] and not os.path.exists(self.args['liberty-file']):
262
217
  self.error(f'--liberty-file={self.args["liberty-file"]} file does not exist')
263
218
 
@@ -273,20 +228,7 @@ class CommandSynthSlangYosys(CommandSynth, ToolSlangYosys):
273
228
  for inst in yosys_blackbox_list:
274
229
  lines.append('blackbox ' + inst)
275
230
 
276
- lines += self.args.get('yosys-pre-synth', [])
277
- lines.append(synth_command)
278
-
279
- # TODO(drew): I need a blackbox flow here? Or a memory_libmap?
280
- # --> https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/memory_libmap.html
281
- # TODO(drew): can I run multiple liberty files?
282
- if self.args['liberty-file']:
283
- lines += [
284
- 'dfflibmap -liberty ' + self.args['liberty-file'],
285
- #'memory_libmap -lib ' + self.args['liberty-file'], # Has to be unzipped?
286
- 'abc -liberty ' + self.args['liberty-file'],
287
- ]
288
-
289
- lines.append(f'write_verilog {self.yosys_v_path}')
231
+ lines += self.get_synth_command_lines()
290
232
  f.write('\n'.join(lines))
291
233
 
292
234
  synth_command_list = util.ShellCommandList(
@@ -296,74 +238,7 @@ class CommandSynthSlangYosys(CommandSynth, ToolSlangYosys):
296
238
  return synth_command_list
297
239
 
298
240
 
299
- def _create_sta_f(self) -> list:
300
-
301
- if not self.args['sta']:
302
- return []
303
-
304
- if not self.args['liberty-file']:
305
- self.error('--sta is set, but need to also set --liberty-file=<file>')
306
-
307
- if self.args['sdc-file']:
308
- if not os.path.exists(self.args['sdc-file']):
309
- self.error(f'--sdc-file={self.args["sdc-file"]} file does not exist')
310
-
311
- if not self.sta_exe:
312
- self.error(f'--sta is set, but "sta" was not found in PATH, see: {self._URL}')
313
-
314
- sta_command_list = util.ShellCommandList(
315
- [ self.sta_exe, '-no_init', '-exit', 'sta.f' ],
316
- tee_fpath = 'sta.log'
317
- )
318
-
319
- # Need to create sta.f:
320
- if self.args['sdc-file']:
321
- sdc_path = self.args['sdc-file']
322
- else:
323
- # Need to create sdc.f:
324
- sdc_path = 'sdc.f'
325
- self._create_sdc_f()
326
-
327
- with open(os.path.join(self.args['work-dir'], 'sta.f'), 'w',
328
- encoding='utf-8') as f:
329
- lines = [
330
- 'read_liberty ' + self.args['liberty-file'],
331
- 'read_verilog ' + self.yosys_v_path,
332
- 'link_design ' + self.args['top'],
333
- 'read_sdc ' + sdc_path,
334
- 'report_checks',
335
- ]
336
- f.write('\n'.join(lines))
337
-
338
- return util.ShellCommandList(
339
- sta_command_list,
340
- tee_fpath = 'sta.log'
341
- )
342
-
343
-
344
- def _create_sdc_f(self) -> None:
345
- if self.args['sdc-file']:
346
- # already exists from args, return b/c nothing to create.
347
- return
348
-
349
- with open(os.path.join(self.args['work-dir'], 'sdc.f'), 'w',
350
- encoding='utf-8') as f:
351
- clock_name = self.args['clock-name']
352
- period = self.args['clock-ns']
353
- name_not_equal_clocks_str = f'NAME !~ "{clock_name}"'
354
- lines = [
355
- f'create_clock -add -name {clock_name} -period {period} [get_ports ' \
356
- + '{' + clock_name + '}];',
357
- f'set_input_delay -max {self.args["idelay-ns"]} -clock {clock_name}' \
358
- + ' [get_ports * -filter {DIRECTION == IN && ' \
359
- + name_not_equal_clocks_str + '}];',
360
- f'set_output_delay -max {self.args["odelay-ns"]} -clock {clock_name}' \
361
- + ' [get_ports * -filter {DIRECTION == OUT}];',
362
- ]
363
- f.write('\n'.join(lines))
364
-
365
-
366
- class CommandElabSlangYosys(CommandSynthSlangYosys):
241
+ class CommandElabSlangYosys(CommandSynthSlangYosys): # pylint: disable=too-many-ancestors
367
242
  '''CommandSynthSlangYosys is a command handler for: eda synth --tool=slang_yosys
368
243
 
369
244
  Runs slang-yosys as elab only (does not run the synthesis portion), but is
@@ -82,11 +82,12 @@ class VerilatorSim(CommandSim, ToolVerilator):
82
82
  })
83
83
 
84
84
  self.args_help.update({
85
- 'waves': 'Include waveforms, if possible for Verilator by applying' \
86
- + ' simulation runtime arg +trace. User will need SV code to interpret the plusarg' \
87
- + ' and apply $dumpfile("dump.fst").',
88
- 'dump-vcd': 'If using --waves, apply simulation runtime arg +trace=vcd. User' \
89
- + ' will need SV code to interpret the plusarg and apply $dumpfile("dump.vcd").',
85
+ 'waves': ('Include waveforms, if possible for Verilator by applying'
86
+ ' simulation runtime arg +trace. User will need SV code to interpret the'
87
+ 'plusarg and apply $dumpfile("dump.fst").'),
88
+ 'dump-vcd': ('If using --waves, apply simulation runtime arg +trace=vcd. User'
89
+ ' will need SV code to interpret the plusarg and apply'
90
+ ' $dumpfile("dump.vcd").'),
90
91
  'lint-only': 'Run verilator with --lint-only, instead of --binary',
91
92
  'gui': 'Not supported for Verilator',
92
93
  'cc-mode': 'Run verilator with --cc, requires a sim_main.cpp or similar sources',
@@ -227,9 +228,10 @@ class VerilatorSim(CommandSim, ToolVerilator):
227
228
  # +define+{k}={v}, but also for SystemVerilog plusargs
228
229
  verilate_command_list += [ f'+define+{k}={sanitize_defines_for_sh(v)}' ]
229
230
 
230
- if (len(self.files_sv) + len(self.files_v)) == 0:
231
- self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
232
- 'cannot call verilator')
231
+ if not self.files_sv and not self.files_v:
232
+ if not self.args['stop-before-compile']:
233
+ self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
234
+ 'cannot call verilator')
233
235
 
234
236
  verilate_command_list += list(self.files_sv) + list(self.files_v)
235
237
 
opencos/tools/vivado.py CHANGED
@@ -720,7 +720,6 @@ class CommandUploadVivado(CommandUpload, ToolVivado):
720
720
  'host': "localhost",
721
721
  'port': 3121,
722
722
  'tcl-file': "upload.tcl",
723
- 'test-mode': False,
724
723
  })
725
724
  # TODO(drew): Add self.args_help.update({...})
726
725