opencos-eda 0.2.38__tar.gz → 0.2.40__tar.gz
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_eda-0.2.38/opencos_eda.egg-info → opencos_eda-0.2.40}/PKG-INFO +1 -1
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/multi.py +7 -3
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/sweep.py +12 -4
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_base.py +118 -17
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/iverilog.py +4 -2
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/modelsim_ase.py +4 -3
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/verilator.py +10 -8
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/vivado.py +0 -1
- {opencos_eda-0.2.38 → opencos_eda-0.2.40/opencos_eda.egg-info}/PKG-INFO +1 -1
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/pyproject.toml +1 -1
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/LICENSE +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/LICENSE.spdx +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/README.md +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/__init__.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/_version.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/_waves_pkg.sv +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/__init__.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/build.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/elab.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/export.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/flist.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/open.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/proj.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/sim.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/synth.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/targets.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/upload.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/commands/waves.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/deps_helpers.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/deps_schema.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_config.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_config_defaults.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_config_max_verilator_waivers.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_config_reduced.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_deps_bash_completion.bash +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_extract_targets.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/eda_tool_helper.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/export_helper.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/export_json_convert.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/files.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/names.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/oc_cli.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/pcie.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/peakrdl_cleanup.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/seed.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/__init__.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/custom_config.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/deps_files/command_order/DEPS.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/helpers.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_build.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_deps_helpers.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_deps_schema.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_eda.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_eda_elab.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_eda_synth.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_oc_cli.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tests/test_tools.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/__init__.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/invio.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/invio_helpers.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/invio_yosys.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/questa.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/slang.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/slang_yosys.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/surelog.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/tabbycad_yosys.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/tools/yosys.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos/util.py +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos_eda.egg-info/SOURCES.txt +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos_eda.egg-info/dependency_links.txt +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos_eda.egg-info/entry_points.txt +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos_eda.egg-info/requires.txt +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/opencos_eda.egg-info/top_level.txt +0 -0
- {opencos_eda-0.2.38 → opencos_eda-0.2.40}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.40
|
|
4
4
|
Summary: A simple Python package for wrapping RTL simuliatons and synthesis
|
|
5
5
|
Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/cognichip/opencos
|
|
@@ -392,7 +392,9 @@ class CommandMulti(CommandParallel):
|
|
|
392
392
|
# Special case for 'multi' --export-jsonl, run reach child with --export-json
|
|
393
393
|
command_list.append('--export-json')
|
|
394
394
|
if tool and len(all_multi_tools) > 1:
|
|
395
|
-
command_list.append(f'--
|
|
395
|
+
command_list.append(f'--job-name={short_target}.{command}.{tool}')
|
|
396
|
+
else:
|
|
397
|
+
command_list.append(f'--job-name={short_target}.{command}')
|
|
396
398
|
|
|
397
399
|
def append_jobs_from_targets(self, args:list):
|
|
398
400
|
'''Helper method in CommandMulti to apply 'args' (list) to all self.targets,
|
|
@@ -430,13 +432,15 @@ class CommandMulti(CommandParallel):
|
|
|
430
432
|
type(self.args['single-timeout']) in [int, str]:
|
|
431
433
|
command_list = ['timeout', str(self.args['single-timeout'])] + command_list
|
|
432
434
|
|
|
433
|
-
name = target
|
|
435
|
+
name = self.get_name_from_target(target)
|
|
434
436
|
if tool and (len(all_multi_tools) > 1 or self.command_name == 'tools-multi'):
|
|
435
|
-
name
|
|
437
|
+
name += f' ({tool})'
|
|
436
438
|
|
|
437
439
|
this_job_dict = {
|
|
438
440
|
'name' : name,
|
|
439
441
|
'index' : len(self.jobs),
|
|
442
|
+
'command': command,
|
|
443
|
+
'target': target,
|
|
440
444
|
'command_list' : command_list
|
|
441
445
|
}
|
|
442
446
|
if tool:
|
|
@@ -113,6 +113,9 @@ class CommandSweep(CommandDesign, CommandParallel):
|
|
|
113
113
|
util.debug(f"Sweep: arg_tokens: '{arg_tokens}'")
|
|
114
114
|
util.debug(f"Sweep: target: '{self.sweep_target}'")
|
|
115
115
|
|
|
116
|
+
if not self.sweep_target:
|
|
117
|
+
self.error(f"Sweep can only take one target, found none, args: {unparsed}")
|
|
118
|
+
|
|
116
119
|
# now create the list of jobs, support one axis
|
|
117
120
|
self.jobs = []
|
|
118
121
|
|
|
@@ -197,15 +200,20 @@ class CommandSweep(CommandDesign, CommandParallel):
|
|
|
197
200
|
f"target={self.sweep_target}, arg_tokens={arg_tokens},",
|
|
198
201
|
f"sweep_axis_list={sweep_axis_list}")
|
|
199
202
|
if not sweep_axis_list:
|
|
200
|
-
# we aren't sweeping anything, create one job
|
|
201
|
-
|
|
203
|
+
# we aren't sweeping anything, create one job:
|
|
204
|
+
# name {target}.{command}[.sweep_value,.sweep_value,...]
|
|
205
|
+
snapshot_name = self.get_name_from_target(self.sweep_target)
|
|
206
|
+
snapshot_name = snapshot_name.replace(os.sep, '_') \
|
|
207
|
+
+ f'.{self.single_command}{sweep_string}'
|
|
202
208
|
eda_path = get_eda_exec('sweep')
|
|
203
209
|
self.jobs.append({
|
|
204
210
|
'name' : snapshot_name,
|
|
205
211
|
'index' : len(self.jobs),
|
|
212
|
+
'command': self.single_command,
|
|
213
|
+
'target': self.sweep_target,
|
|
206
214
|
'command_list' : (
|
|
207
215
|
[eda_path, self.single_command, self.sweep_target,
|
|
208
|
-
'--
|
|
216
|
+
f'--job-name={snapshot_name}'] + arg_tokens
|
|
209
217
|
)
|
|
210
218
|
})
|
|
211
219
|
return
|
|
@@ -221,7 +229,7 @@ class CommandSweep(CommandDesign, CommandParallel):
|
|
|
221
229
|
this_arg_tokens.append(f'{lhs}{operator}{v}')
|
|
222
230
|
|
|
223
231
|
v_string = f"{v}".replace('.','p')
|
|
224
|
-
this_sweep_string = sweep_string + f"
|
|
232
|
+
this_sweep_string = sweep_string + f".{lhs_trimmed}_{v_string}"
|
|
225
233
|
|
|
226
234
|
self.expand_sweep_axis(
|
|
227
235
|
arg_tokens=this_arg_tokens,
|
|
@@ -11,6 +11,7 @@ import signal
|
|
|
11
11
|
import sys
|
|
12
12
|
import threading
|
|
13
13
|
import time
|
|
14
|
+
from pathlib import Path
|
|
14
15
|
|
|
15
16
|
import opencos
|
|
16
17
|
from opencos import seed, deps_helpers, util, files
|
|
@@ -177,6 +178,7 @@ class Command:
|
|
|
177
178
|
"job-name" : "", # this is used to create a certain dir under "eda_dir"
|
|
178
179
|
"work-dir" : "", # this can be used to run the job in a certain dir, else it will be <eda-dir>/<job-name> else <eda-dir>/<target>_<command>
|
|
179
180
|
"sub-work-dir" : "", # this can be used to name the dir built under <eda-dir>, which seems to be same function as job-name??
|
|
181
|
+
"work-dir-use-target-dir": False,
|
|
180
182
|
"suffix" : "",
|
|
181
183
|
"design" : "", # not sure how this relates to top
|
|
182
184
|
'export': False,
|
|
@@ -184,24 +186,31 @@ class Command:
|
|
|
184
186
|
'export-json': False, # generates an export.json suitable for a testrunner, if possible for self.command.
|
|
185
187
|
'enable-tags': [],
|
|
186
188
|
'disable-tags': [],
|
|
189
|
+
'test-mode': False,
|
|
187
190
|
})
|
|
188
191
|
self.args_help.update({
|
|
189
|
-
'stop-before-compile': 'stop this run before any compile (if possible for tool) and'
|
|
190
|
-
|
|
192
|
+
'stop-before-compile': ('stop this run before any compile (if possible for tool) and'
|
|
193
|
+
' save .sh scripts in eda-dir/'),
|
|
191
194
|
'eda-dir': 'relative directory where eda logs are saved',
|
|
192
195
|
'export': 'export results for these targets in eda-dir',
|
|
193
196
|
'export-run': 'export, and run, results for these targets in eda-dir',
|
|
194
197
|
'export-json': 'export, and save a JSON file per target',
|
|
195
|
-
'work-dir': 'Optional override for working directory, often defaults to
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
'work-dir': ('Optional override for working directory, often defaults to'
|
|
199
|
+
' ./eda.work/<top>.<command>'),
|
|
200
|
+
"work-dir-use-target-dir": ('Set the work-dir to be the same as the in-place location'
|
|
201
|
+
' where the target (DEPS) exists'),
|
|
202
|
+
'enable-tags': ('DEPS markup tag names to be force enabled for this'
|
|
203
|
+
' command (mulitple appends to list).'),
|
|
204
|
+
'diable-tags': ('DEPS markup tag names to be disabled (even if they'
|
|
205
|
+
' match the criteria) for this command (mulitple appends to list).'
|
|
206
|
+
' --disable-tags has higher precedence than --enable-tags.'),
|
|
207
|
+
'test-mode': ('command and tool dependent, usually stops the command early without'
|
|
208
|
+
' executing.'),
|
|
201
209
|
})
|
|
202
210
|
self.modified_args = {}
|
|
203
211
|
self.config = copy.deepcopy(config) # avoid external modifications.
|
|
204
212
|
self.target = ""
|
|
213
|
+
self.target_path = ""
|
|
205
214
|
self.status = 0
|
|
206
215
|
|
|
207
216
|
def error(self, *args, **kwargs):
|
|
@@ -223,8 +232,18 @@ class Command:
|
|
|
223
232
|
|
|
224
233
|
def create_work_dir(self):
|
|
225
234
|
util.debug(f"create_work_dir: {self.args['eda-dir']=} {self.args['work-dir']=}")
|
|
226
|
-
if
|
|
227
|
-
|
|
235
|
+
if self.args['work-dir-use-target-dir']:
|
|
236
|
+
if not self.target_path:
|
|
237
|
+
self.target_path = '.'
|
|
238
|
+
util.info(f"create_work_dir: --work-dir-use-target-dir: using:",
|
|
239
|
+
f"{os.path.abspath(self.target_path)}",
|
|
240
|
+
f'target={self.target}')
|
|
241
|
+
self.args['work-dir'] = self.target_path
|
|
242
|
+
self.args['sub-work-dir'] = ''
|
|
243
|
+
return self.args['work-dir']
|
|
244
|
+
|
|
245
|
+
if not os.path.exists(self.args['eda-dir']):
|
|
246
|
+
util.safe_mkdir(self.args['eda-dir'])
|
|
228
247
|
util.info(f"create_work_dir: created {self.args['eda-dir']}")
|
|
229
248
|
if self.args['design'] == "":
|
|
230
249
|
if ('top' in self.args) and (self.args['top'] != ""):
|
|
@@ -250,14 +269,35 @@ class Command:
|
|
|
250
269
|
if (os.path.exists(self.args['work-dir'])):
|
|
251
270
|
if os.path.exists(keep_file) and not self.args['force']:
|
|
252
271
|
self.error(f"Cannot remove old work dir due to '{keep_file}'")
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
272
|
+
elif os.path.abspath(self.args['work-dir']) in os.getcwd():
|
|
273
|
+
# This effectively checks if
|
|
274
|
+
# --work-dir=.
|
|
275
|
+
# --work-dir=$PWD
|
|
276
|
+
# --work-dir=/some/path/almost/here
|
|
277
|
+
# Allow it, but preserve the existing directory, we don't want to blow away
|
|
278
|
+
# files up-heir from us.
|
|
279
|
+
# Enables support for --work-dir=.
|
|
280
|
+
util.info(f"Not removing existing work-dir: '{self.args['work-dir']}' is within {os.getcwd()=}")
|
|
281
|
+
elif str(Path(self.args['work-dir'])).startswith(str(Path('/'))):
|
|
282
|
+
# Do not allow other absolute path work dirs if it already exists.
|
|
283
|
+
# This prevents you from --work-dir=~ and eda wipes out your home dir.
|
|
284
|
+
self.error(f'Cannot use work-dir={self.args["work-dir"]} starting with absolute path "/"')
|
|
285
|
+
elif str(Path('..')) in str(Path(self.args['work-dir'])):
|
|
286
|
+
# Do not allow other ../ work dirs if it already exists.
|
|
287
|
+
self.error(f'Cannot use work-dir={self.args["work-dir"]} with up-hierarchy ../ paths')
|
|
288
|
+
else:
|
|
289
|
+
# If we made it this far, on a directory that exists, that appears safe
|
|
290
|
+
# to delete and re-create:
|
|
291
|
+
util.info(f"Removing previous '{self.args['work-dir']}'")
|
|
292
|
+
shutil.rmtree(self.args['work-dir'])
|
|
293
|
+
util.safe_mkdir(self.args['work-dir'])
|
|
294
|
+
util.debug(f'create_work_dir: created {self.args["work-dir"]}')
|
|
295
|
+
else:
|
|
296
|
+
util.safe_mkdir(self.args['work-dir'])
|
|
297
|
+
util.debug(f'create_work_dir: created {self.args["work-dir"]}')
|
|
257
298
|
if (self.args['keep']):
|
|
258
299
|
open(keep_file, 'w').close()
|
|
259
|
-
util.debug(f'create_work_dir: created {keep_file}')
|
|
260
|
-
util.info(f'create_work_dir: created {self.args["work-dir"]}')
|
|
300
|
+
util.debug(f'create_work_dir: created {keep_file=}')
|
|
261
301
|
return self.args['work-dir']
|
|
262
302
|
|
|
263
303
|
def exec(self, work_dir, command_list, background=False, stop_on_error=True,
|
|
@@ -858,7 +898,7 @@ class CommandDesign(Command):
|
|
|
858
898
|
# self.target is a name we grab for the job (i.e. for naming work dir etc). we don't want the path prefix.
|
|
859
899
|
# TODO: too messy -- there's also a self.target, args['job-name'], args['work-dir'], args['design'], args['top'], args['sub-work-dir'] ...
|
|
860
900
|
|
|
861
|
-
self.target = os.path.
|
|
901
|
+
self.target_path, self.target = os.path.split(target)
|
|
862
902
|
|
|
863
903
|
if target in self.targets_dict:
|
|
864
904
|
# If we're encountered this target before, stop. We're not traversing again.
|
|
@@ -1361,6 +1401,8 @@ class CommandParallel(Command):
|
|
|
1361
1401
|
fancy_mode = util.args['fancy'] and (num_parallel > 1) and (num_parallel <= (lines-6))
|
|
1362
1402
|
multi_cwd = util.getcwd() + os.sep
|
|
1363
1403
|
|
|
1404
|
+
self.patch_jobs_for_duplicate_target_names()
|
|
1405
|
+
|
|
1364
1406
|
if run_parallel:
|
|
1365
1407
|
# we are doing this multi-threaded
|
|
1366
1408
|
util.info(f"Parallel: Running multi-threaded, starting {num_parallel} workers")
|
|
@@ -1519,6 +1561,10 @@ class CommandParallel(Command):
|
|
|
1519
1561
|
self.status = 0 if len(self.jobs_status) == 0 else max(self.jobs_status)
|
|
1520
1562
|
util.fancy_stop()
|
|
1521
1563
|
|
|
1564
|
+
@staticmethod
|
|
1565
|
+
def get_name_from_target(target: str) -> str:
|
|
1566
|
+
return target.replace('../', '').lstrip('./')
|
|
1567
|
+
|
|
1522
1568
|
|
|
1523
1569
|
def update_args_list(self, args: list, tool: str) -> None:
|
|
1524
1570
|
'''Modfies list args, using allow-listed known top-level args:
|
|
@@ -1572,3 +1618,58 @@ class CommandParallel(Command):
|
|
|
1572
1618
|
# Remove unparsed args starting with '+', since those are commonly sent downstream to
|
|
1573
1619
|
# single job (example, CommandSim plusargs).
|
|
1574
1620
|
return [x for x in single_cmd_unparsed if not x.startswith('+')]
|
|
1621
|
+
|
|
1622
|
+
|
|
1623
|
+
def patch_jobs_for_duplicate_target_names(self) -> None:
|
|
1624
|
+
'''Examines list self.jobs, and if leaf target names are duplicate will
|
|
1625
|
+
patch each command's job-name to:
|
|
1626
|
+
--job-name=path.leaf.command[.tool]
|
|
1627
|
+
'''
|
|
1628
|
+
|
|
1629
|
+
def get_job_name(job_dict: dict) -> str:
|
|
1630
|
+
'''Fishes the job-name out of an entry in self.jobs'''
|
|
1631
|
+
for i, item in enumerate(job_dict['command_list']):
|
|
1632
|
+
if item.startswith('--job-name='):
|
|
1633
|
+
_, name = item.split('--job-name=')
|
|
1634
|
+
return name
|
|
1635
|
+
elif item == '--job-name':
|
|
1636
|
+
return job_dict['command_list'][i + 1]
|
|
1637
|
+
return ''
|
|
1638
|
+
|
|
1639
|
+
def replace_job_name(job_dict: dict, new_job_name: str) -> dict:
|
|
1640
|
+
'''Replaces the job-name in an entry in self.jobs'''
|
|
1641
|
+
for i, item in enumerate(job_dict['command_list']):
|
|
1642
|
+
if item.startswith('--job-name='):
|
|
1643
|
+
job_dict['command_list'][i] = '--job-name=' + new_job_name
|
|
1644
|
+
return job_dict
|
|
1645
|
+
elif item == '--job-name':
|
|
1646
|
+
job_dict['command_list'][i + 1] = new_job_name
|
|
1647
|
+
return job_dict
|
|
1648
|
+
return job_dict
|
|
1649
|
+
|
|
1650
|
+
|
|
1651
|
+
job_names_count_dict = {}
|
|
1652
|
+
for job_dict in self.jobs:
|
|
1653
|
+
|
|
1654
|
+
key = get_job_name(job_dict)
|
|
1655
|
+
if not key:
|
|
1656
|
+
self.error(f'{job_dict=} needs to have a --job-name= arg attached')
|
|
1657
|
+
if key not in job_names_count_dict:
|
|
1658
|
+
job_names_count_dict[key] = 1
|
|
1659
|
+
else:
|
|
1660
|
+
job_names_count_dict[key] += 1
|
|
1661
|
+
|
|
1662
|
+
for i, job_dict in enumerate(self.jobs):
|
|
1663
|
+
key = get_job_name(job_dict)
|
|
1664
|
+
if job_names_count_dict[key] < 2:
|
|
1665
|
+
continue
|
|
1666
|
+
|
|
1667
|
+
tpath, _ = os.path.split(job_dict['target'])
|
|
1668
|
+
|
|
1669
|
+
# prepend path information to job-name:
|
|
1670
|
+
patched_sub_work_dir = False
|
|
1671
|
+
patched_target_path = os.path.relpath(tpath).replace(os.sep, '_')
|
|
1672
|
+
new_job_name = f'{patched_target_path}.{key}'
|
|
1673
|
+
new_job_dict = replace_job_name(job_dict, new_job_name)
|
|
1674
|
+
self.jobs[i] = new_job_dict
|
|
1675
|
+
util.debug(f'Patched job {job_dict["name"]}: --job-name={new_job_name}')
|
|
@@ -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
|
-
|
|
160
|
-
|
|
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
|
|
182
|
-
|
|
183
|
-
|
|
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)
|
|
@@ -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
|
-
|
|
87
|
-
|
|
88
|
-
'dump-vcd': 'If using --waves, apply simulation runtime arg +trace=vcd. User'
|
|
89
|
-
|
|
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
|
|
231
|
-
|
|
232
|
-
|
|
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
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.40
|
|
4
4
|
Summary: A simple Python package for wrapping RTL simuliatons and synthesis
|
|
5
5
|
Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/cognichip/opencos
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|