opencos-eda 0.2.36__py3-none-any.whl → 0.2.38__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.
- opencos/commands/__init__.py +2 -0
- opencos/commands/targets.py +49 -0
- opencos/eda.py +39 -99
- opencos/eda_base.py +8 -3
- opencos/eda_config.py +20 -11
- opencos/eda_config_defaults.yml +28 -1
- opencos/eda_config_reduced.yml +0 -1
- opencos/eda_deps_bash_completion.bash +1 -1
- opencos/eda_extract_targets.py +37 -19
- opencos/files.py +2 -2
- opencos/tests/helpers.py +7 -6
- opencos/tests/test_eda.py +22 -0
- opencos/tools/invio.py +4 -5
- opencos/tools/invio_yosys.py +28 -20
- opencos/tools/slang_yosys.py +10 -135
- opencos/tools/yosys.py +135 -0
- {opencos_eda-0.2.36.dist-info → opencos_eda-0.2.38.dist-info}/METADATA +1 -1
- {opencos_eda-0.2.36.dist-info → opencos_eda-0.2.38.dist-info}/RECORD +23 -22
- {opencos_eda-0.2.36.dist-info → opencos_eda-0.2.38.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.36.dist-info → opencos_eda-0.2.38.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.36.dist-info → opencos_eda-0.2.38.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.36.dist-info → opencos_eda-0.2.38.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.36.dist-info → opencos_eda-0.2.38.dist-info}/top_level.txt +0 -0
opencos/commands/__init__.py
CHANGED
|
@@ -17,6 +17,7 @@ from .sweep import CommandSweep
|
|
|
17
17
|
from .synth import CommandSynth
|
|
18
18
|
from .upload import CommandUpload
|
|
19
19
|
from .waves import CommandWaves
|
|
20
|
+
from .targets import CommandTargets
|
|
20
21
|
|
|
21
22
|
__all__ = [
|
|
22
23
|
'CommandBuild',
|
|
@@ -32,4 +33,5 @@ __all__ = [
|
|
|
32
33
|
'CommandToolsMulti',
|
|
33
34
|
'CommandUpload',
|
|
34
35
|
'CommandWaves',
|
|
36
|
+
'CommandTargets',
|
|
35
37
|
]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'''opencos.commands.targets - command handler for: eda targets [args]
|
|
2
|
+
|
|
3
|
+
Note this command is handled differently than others (such as CommandSim),
|
|
4
|
+
it is generally run as simply
|
|
5
|
+
|
|
6
|
+
> eda targets
|
|
7
|
+
> eda targets <directory>
|
|
8
|
+
> eda targets [directory/]<pattern> [directory2/]<pattern2> ...
|
|
9
|
+
|
|
10
|
+
uses no tools and will print a pretty list of targets to stdout.
|
|
11
|
+
'''
|
|
12
|
+
|
|
13
|
+
# Note - similar code waiver, tricky to eliminate it with inheritance when
|
|
14
|
+
# calling reusable methods.
|
|
15
|
+
# pylint: disable=R0801
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
from opencos import eda_extract_targets
|
|
20
|
+
from opencos.eda_base import Command
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CommandTargets:
|
|
24
|
+
'''command handler for: eda targets'''
|
|
25
|
+
|
|
26
|
+
command_name = 'targets'
|
|
27
|
+
|
|
28
|
+
def __init__(self, config: dict):
|
|
29
|
+
# We don't inherit opencos.eda_base.Command, so we have to set a few
|
|
30
|
+
# member vars for Command.help to work.
|
|
31
|
+
self.args = {}
|
|
32
|
+
self.args_help = {}
|
|
33
|
+
self.config = config
|
|
34
|
+
self.status = 0
|
|
35
|
+
|
|
36
|
+
def process_tokens( # pylint: disable=unused-argument
|
|
37
|
+
self, tokens: list, process_all: bool = True,
|
|
38
|
+
pwd: str = os.getcwd()
|
|
39
|
+
) -> list:
|
|
40
|
+
'''This is effectively our 'run' method, entrypoint from opencos.eda.main'''
|
|
41
|
+
|
|
42
|
+
eda_extract_targets.run(partial_paths=tokens, base_path=pwd)
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
def help(self, tokens: list) -> None:
|
|
46
|
+
'''Since we don't inherit from opencos.eda_base.Command, need our own help
|
|
47
|
+
method
|
|
48
|
+
'''
|
|
49
|
+
Command.help(self, tokens=tokens)
|
opencos/eda.py
CHANGED
|
@@ -10,6 +10,7 @@ import re
|
|
|
10
10
|
import signal
|
|
11
11
|
import argparse
|
|
12
12
|
import shlex
|
|
13
|
+
import importlib.util
|
|
13
14
|
|
|
14
15
|
import opencos
|
|
15
16
|
from opencos import util, files
|
|
@@ -19,7 +20,6 @@ from opencos.eda_base import Tool, which_tool
|
|
|
19
20
|
|
|
20
21
|
# Globals
|
|
21
22
|
|
|
22
|
-
debug_respawn = False
|
|
23
23
|
util.progname = "EDA"
|
|
24
24
|
|
|
25
25
|
|
|
@@ -30,37 +30,25 @@ util.progname = "EDA"
|
|
|
30
30
|
# eda command (such as, command: eda sim) is handled by which class (such as class: CommandSim)
|
|
31
31
|
# These are also overriden depending on the tool, for example --tool verilator sets
|
|
32
32
|
# "sim": CommandSimVerilator.
|
|
33
|
-
def init_config(
|
|
33
|
+
def init_config(
|
|
34
|
+
config: dict, quiet: bool = False, tool=None, run_auto_tool_setup: bool = True
|
|
35
|
+
) -> dict:
|
|
34
36
|
'''Sets or clears entries in config (dict) so tools can be re-loaded.'''
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
config['command_handler'] = {
|
|
46
|
-
"sim" : CommandSim,
|
|
47
|
-
"elab" : CommandElab,
|
|
48
|
-
"synth" : CommandSynth,
|
|
49
|
-
"flist" : CommandFList,
|
|
50
|
-
"proj" : CommandProj,
|
|
51
|
-
"multi" : CommandMulti,
|
|
52
|
-
"tools-multi" : CommandToolsMulti,
|
|
53
|
-
"sweep" : CommandSweep,
|
|
54
|
-
"build" : CommandBuild,
|
|
55
|
-
"waves" : CommandWaves,
|
|
56
|
-
"upload" : CommandUpload,
|
|
57
|
-
"open" : CommandOpen,
|
|
58
|
-
"export" : CommandExport,
|
|
59
|
-
}
|
|
38
|
+
# For key DEFAULT_HANDLERS, we'll update config['command_handler'] with
|
|
39
|
+
# the actual class using importlib (via opencos.util)
|
|
40
|
+
config['command_handler'] = {}
|
|
41
|
+
for command, str_class in config['DEFAULT_HANDLERS'].items():
|
|
42
|
+
cls = util.import_class_from_string(str_class)
|
|
43
|
+
if not cls:
|
|
44
|
+
util.error(f"config DEFAULT_HANDLERS {command=} {str_class=} could not import")
|
|
45
|
+
else:
|
|
46
|
+
config['command_handler'][command] = cls
|
|
60
47
|
|
|
61
48
|
config['auto_tools_found'] = dict()
|
|
62
49
|
config['tools_loaded'] = set()
|
|
63
|
-
|
|
50
|
+
if run_auto_tool_setup:
|
|
51
|
+
config = auto_tool_setup(config=config, quiet=quiet, tool=tool)
|
|
64
52
|
return config
|
|
65
53
|
|
|
66
54
|
|
|
@@ -154,7 +142,6 @@ def auto_tool_setup(warnings:bool=True, config=None, quiet=False, tool=None) ->
|
|
|
154
142
|
tool='verlator', tool='verilator=/path/to/verilator.exe'
|
|
155
143
|
If so, updates config['auto_tools_order'][tool]['exe']
|
|
156
144
|
'''
|
|
157
|
-
import importlib.util
|
|
158
145
|
|
|
159
146
|
tool = eda_config.update_config_auto_tool_order_for_tool(
|
|
160
147
|
tool=tool, config=config
|
|
@@ -237,7 +224,6 @@ def tool_setup(tool: str, config: dict, quiet: bool = False, auto_setup: bool =
|
|
|
237
224
|
tool='verlator', tool='verilator=/path/to/verilator.exe'
|
|
238
225
|
|
|
239
226
|
'''
|
|
240
|
-
import importlib
|
|
241
227
|
|
|
242
228
|
tool = eda_config.update_config_auto_tool_order_for_tool(
|
|
243
229
|
tool=tool, config=config
|
|
@@ -281,10 +267,7 @@ def tool_setup(tool: str, config: dict, quiet: bool = False, auto_setup: bool =
|
|
|
281
267
|
# skip, already has a tool associated with it, and we're in auto_setup=True
|
|
282
268
|
continue
|
|
283
269
|
|
|
284
|
-
|
|
285
|
-
cls = util.import_class_from_string(str_class_name)
|
|
286
|
-
else:
|
|
287
|
-
cls = globals().get(str_class_name, None)
|
|
270
|
+
cls = util.import_class_from_string(str_class_name)
|
|
288
271
|
|
|
289
272
|
assert issubclass(cls, Tool), f'{str_class_name=} is does not have Tool class associated with it'
|
|
290
273
|
util.debug(f'Setting {cls=} for {command=} in config.command_handler')
|
|
@@ -302,6 +285,7 @@ def process_tokens(tokens: list, original_args: list, config: dict, interactive=
|
|
|
302
285
|
|
|
303
286
|
deferred_tokens = []
|
|
304
287
|
command = ""
|
|
288
|
+
run_auto_tool_setup = True
|
|
305
289
|
|
|
306
290
|
parser = eda_base.get_argparser()
|
|
307
291
|
try:
|
|
@@ -324,22 +308,29 @@ def process_tokens(tokens: list, original_args: list, config: dict, interactive=
|
|
|
324
308
|
if parsed.eda_safe:
|
|
325
309
|
eda_config.update_config_for_eda_safe(config)
|
|
326
310
|
|
|
311
|
+
util.debug(f'eda process_tokens: {parsed=} {unparsed=}')
|
|
312
|
+
|
|
313
|
+
# Attempt to get the 'command' in the unparsed args before we've even
|
|
314
|
+
# set the command handlers (some commands don't use tools).
|
|
315
|
+
for value in unparsed:
|
|
316
|
+
if value in config['DEFAULT_HANDLERS'].keys():
|
|
317
|
+
command = value
|
|
318
|
+
if value in config['command_uses_no_tools']:
|
|
319
|
+
run_auto_tool_setup = False
|
|
320
|
+
unparsed.remove(value)
|
|
321
|
+
break
|
|
322
|
+
|
|
327
323
|
if not interactive:
|
|
328
324
|
# Run init_config() now, we deferred it in main(), but only run it
|
|
329
325
|
# for this tool (or tool=None to figure it out)
|
|
330
|
-
config = init_config(
|
|
326
|
+
config = init_config(
|
|
327
|
+
config, tool=parsed.tool,
|
|
328
|
+
run_auto_tool_setup=run_auto_tool_setup
|
|
329
|
+
)
|
|
331
330
|
if not config:
|
|
332
331
|
util.error(f'eda.py main: problem loading config, {args=}')
|
|
333
332
|
return 3
|
|
334
333
|
|
|
335
|
-
|
|
336
|
-
util.debug(f'eda process_tokens: {parsed=} {unparsed=}')
|
|
337
|
-
for value in unparsed:
|
|
338
|
-
if value in config['command_handler'].keys():
|
|
339
|
-
command = value
|
|
340
|
-
unparsed.remove(value)
|
|
341
|
-
break
|
|
342
|
-
|
|
343
334
|
# Deal with help, now that we have the command (if it was set).
|
|
344
335
|
if parsed.help:
|
|
345
336
|
if not command:
|
|
@@ -363,7 +354,9 @@ def process_tokens(tokens: list, original_args: list, config: dict, interactive=
|
|
|
363
354
|
util.debug(f'{command=}')
|
|
364
355
|
util.debug(f'{sco.config=}')
|
|
365
356
|
util.debug(f'{type(sco)=}')
|
|
366
|
-
if not parsed.tool and
|
|
357
|
+
if not parsed.tool and \
|
|
358
|
+
command not in config.get('command_determines_tool', []) and \
|
|
359
|
+
command not in config.get('command_uses_no_tools', []):
|
|
367
360
|
use_tool = which_tool(command, config)
|
|
368
361
|
util.info(f"--tool not specified, using default for {command=}: {use_tool}")
|
|
369
362
|
|
|
@@ -377,7 +370,7 @@ def process_tokens(tokens: list, original_args: list, config: dict, interactive=
|
|
|
377
370
|
sco.config['eda_original_args'] = original_args
|
|
378
371
|
|
|
379
372
|
setattr(sco, 'command_name', command) # as a safeguard, b/c 'command' is not always passed to 'sco'
|
|
380
|
-
unparsed = sco.process_tokens(deferred_tokens)
|
|
373
|
+
unparsed = sco.process_tokens(tokens=deferred_tokens, pwd=os.getcwd())
|
|
381
374
|
|
|
382
375
|
# query the status from the Command object (0 is pass, > 0 is fail)
|
|
383
376
|
rc = getattr(sco, 'status', 1)
|
|
@@ -439,7 +432,6 @@ def main(*args):
|
|
|
439
432
|
# Handle --config-yml= arg
|
|
440
433
|
config, unparsed = eda_config.get_eda_config(unparsed)
|
|
441
434
|
|
|
442
|
-
|
|
443
435
|
# Note - we used to call: config = init_config(config=config)
|
|
444
436
|
# However, we now defer calling init_config(..) until eda.process_tokens(..)
|
|
445
437
|
|
|
@@ -459,22 +451,8 @@ def main(*args):
|
|
|
459
451
|
config=config)
|
|
460
452
|
|
|
461
453
|
|
|
462
|
-
def main_cli(
|
|
454
|
+
def main_cli() -> None:
|
|
463
455
|
''' Returns None, will exit with return code. Entry point for package script or __main__.'''
|
|
464
|
-
|
|
465
|
-
if support_respawn and '--no-respawn' not in sys.argv:
|
|
466
|
-
# If someone called eda.py directly (aka, __name__ == '__main__'),
|
|
467
|
-
# then we still support a legacy mode of operation - where we check
|
|
468
|
-
# for OC_ROOT (in env, or git repo) to make sure this is the right
|
|
469
|
-
# location of eda.py by calling main_cli(support_respawn=True).
|
|
470
|
-
# Otherwise, we do not respawn $OC_ROOT/bin/eda.py
|
|
471
|
-
# Can also be avoided with --no-respawn.
|
|
472
|
-
|
|
473
|
-
# Note - respawn will never work if calling as a package executable script,
|
|
474
|
-
# which is why our package entrypoint will be main_cli() w/out support_respawn.
|
|
475
|
-
main_maybe_respawn()
|
|
476
|
-
|
|
477
|
-
|
|
478
456
|
signal.signal(signal.SIGINT, signal_handler)
|
|
479
457
|
util.global_exit_allowed = True
|
|
480
458
|
# Strip eda or eda.py from sys.argv, we know who we are if called from __main__:
|
|
@@ -482,46 +460,8 @@ def main_cli(support_respawn=False):
|
|
|
482
460
|
util.exit(rc)
|
|
483
461
|
|
|
484
462
|
|
|
485
|
-
def main_maybe_respawn():
|
|
486
|
-
''' Returns None, will respawn - run - exit, or will return and the command
|
|
487
|
-
|
|
488
|
-
is expected to run in main_cli()'''
|
|
489
|
-
|
|
490
|
-
# First we check if we are respawning
|
|
491
|
-
this_path = os.path.realpath(__file__)
|
|
492
|
-
if debug_respawn: util.info(f"RESPAWN: this_path : '{this_path}'")
|
|
493
|
-
oc_root = util.get_oc_root()
|
|
494
|
-
if debug_respawn: util.info(f"RESPAWN: oc_root : '{oc_root}'")
|
|
495
|
-
cwd = util.getcwd()
|
|
496
|
-
if debug_respawn: util.info(f"RESPAWN: cwd : '{cwd}'")
|
|
497
|
-
if oc_root:
|
|
498
|
-
new_paths = [
|
|
499
|
-
os.path.join(oc_root, 'opencos', 'eda.py'),
|
|
500
|
-
os.path.join(oc_root, 'bin', 'eda'),
|
|
501
|
-
]
|
|
502
|
-
if debug_respawn: util.info(f"RESPAWN: {new_paths=} {this_path=}")
|
|
503
|
-
if this_path not in new_paths and os.path.exists(new_paths[0]):
|
|
504
|
-
# we are not the correct version of EDA for this Git repo, we should respawn
|
|
505
|
-
util.info(f"{this_path} respawning {new_paths[0]} in {cwd} with --no-respawn")
|
|
506
|
-
sys.argv[0] = new_paths[0]
|
|
507
|
-
sys.argv.insert(1, '--no-respawn')
|
|
508
|
-
proc = subprocess.Popen(sys.argv, shell=0, cwd=cwd, universal_newlines=True)
|
|
509
|
-
while True:
|
|
510
|
-
try:
|
|
511
|
-
proc.communicate()
|
|
512
|
-
break
|
|
513
|
-
except KeyboardInterrupt:
|
|
514
|
-
continue
|
|
515
|
-
# get exit status from proc and return it
|
|
516
|
-
util.exit(proc.returncode, quiet=True)
|
|
517
|
-
else:
|
|
518
|
-
if debug_respawn: util.info(f"RESPAWN: {oc_root=} respawn not necessary")
|
|
519
|
-
else:
|
|
520
|
-
if debug_respawn: util.info("RESPAWN: respawn not necessary")
|
|
521
|
-
|
|
522
|
-
|
|
523
463
|
if __name__ == '__main__':
|
|
524
|
-
main_cli(
|
|
464
|
+
main_cli()
|
|
525
465
|
|
|
526
466
|
# IDEAS:
|
|
527
467
|
# * options with no default (i.e. if user doesn't override, THEN we set it, like "seed" or "work-dir") can be given a
|
opencos/eda_base.py
CHANGED
|
@@ -550,7 +550,7 @@ class Command:
|
|
|
550
550
|
self.set_tool_defines()
|
|
551
551
|
|
|
552
552
|
|
|
553
|
-
def help(self, tokens: list = []):
|
|
553
|
+
def help(self, tokens: list = []) -> None:
|
|
554
554
|
'''Since we don't quite follow standard argparger help()/usage(), we'll format our own
|
|
555
555
|
|
|
556
556
|
if self.args_help has additional help information.
|
|
@@ -569,8 +569,13 @@ class Command:
|
|
|
569
569
|
|
|
570
570
|
print_base_help()
|
|
571
571
|
lines = []
|
|
572
|
+
if not self.args:
|
|
573
|
+
print(f'Unparsed args: {tokens}')
|
|
574
|
+
return
|
|
575
|
+
|
|
572
576
|
if self.command_name:
|
|
573
|
-
lines.append(f"Generic help for command='{self.command_name}'
|
|
577
|
+
lines.append(f"Generic help for command='{self.command_name}'"
|
|
578
|
+
f" (using '{self.__class__.__name__}')")
|
|
574
579
|
else:
|
|
575
580
|
lines.append(f"Generic help (from class Command):")
|
|
576
581
|
|
|
@@ -752,7 +757,7 @@ class CommandDesign(Command):
|
|
|
752
757
|
# token = '\'+define+OC_ROOT="/foo/bar/opencos"\''
|
|
753
758
|
# So we strip all outer ' or " on the plusarg:
|
|
754
759
|
plusarg = util.strip_outer_quotes(plusarg)
|
|
755
|
-
if pwd
|
|
760
|
+
if not pwd:
|
|
756
761
|
pwd = ''
|
|
757
762
|
|
|
758
763
|
if plusarg.startswith('+define+'):
|
opencos/eda_config.py
CHANGED
|
@@ -15,9 +15,11 @@ class Defaults:
|
|
|
15
15
|
home_override_config_yml = os.path.join(
|
|
16
16
|
os.environ.get('HOME', ''), '.opencos-eda', 'EDA_CONFIG.yml'
|
|
17
17
|
)
|
|
18
|
-
|
|
18
|
+
opencos_config_yml = 'eda_config_defaults.yml'
|
|
19
|
+
config_yml = ''
|
|
19
20
|
|
|
20
21
|
supported_config_keys = set([
|
|
22
|
+
'DEFAULT_HANDLERS',
|
|
21
23
|
'defines',
|
|
22
24
|
'dep_command_enables',
|
|
23
25
|
'dep_tags_enables',
|
|
@@ -26,10 +28,11 @@ class Defaults:
|
|
|
26
28
|
'bare_plusarg_supported',
|
|
27
29
|
'dep_sub',
|
|
28
30
|
'vars',
|
|
29
|
-
'tools',
|
|
30
|
-
'auto_tools_order',
|
|
31
31
|
'file_extensions',
|
|
32
32
|
'command_determines_tool',
|
|
33
|
+
'command_uses_no_tools',
|
|
34
|
+
'tools',
|
|
35
|
+
'auto_tools_order',
|
|
33
36
|
])
|
|
34
37
|
supported_config_auto_tools_order_keys = set([
|
|
35
38
|
'exe', 'handlers', 'requires_env', 'requires_py', 'requires_cmd',
|
|
@@ -53,6 +56,14 @@ class Defaults:
|
|
|
53
56
|
])
|
|
54
57
|
|
|
55
58
|
|
|
59
|
+
if os.path.exists(Defaults.environ_override_config_yml):
|
|
60
|
+
Defaults.config_yml = Defaults.environ_override_config_yml
|
|
61
|
+
elif os.path.exists(Defaults.home_override_config_yml):
|
|
62
|
+
Defaults.config_yml = Defaults.home_override_config_yml
|
|
63
|
+
else:
|
|
64
|
+
Defaults.config_yml = Defaults.opencos_config_yml
|
|
65
|
+
|
|
66
|
+
|
|
56
67
|
def find_eda_config_yml_fpath(filename:str, package_search_only=False, package_search_enabled=True) -> str:
|
|
57
68
|
'''Locates the filename (.yml) either from fullpath provided or from the sys.path
|
|
58
69
|
opencos package paths.'''
|
|
@@ -192,15 +203,9 @@ def get_config_merged_with_defaults(config:dict) -> dict:
|
|
|
192
203
|
return default_config
|
|
193
204
|
|
|
194
205
|
def get_argparser() -> argparse.ArgumentParser:
|
|
195
|
-
if os.path.exists(Defaults.environ_override_config_yml):
|
|
196
|
-
default_config_yml = Defaults.environ_override_config_yml
|
|
197
|
-
elif os.path.exists(Defaults.home_override_config_yml):
|
|
198
|
-
default_config_yml = Defaults.home_override_config_yml
|
|
199
|
-
else:
|
|
200
|
-
default_config_yml = Defaults.config_yml
|
|
201
206
|
parser = argparse.ArgumentParser(prog='opencos eda config options', add_help=False, allow_abbrev=False)
|
|
202
|
-
parser.add_argument('--config-yml', type=str, default=
|
|
203
|
-
help=f'YAML filename to use for configuration (default {
|
|
207
|
+
parser.add_argument('--config-yml', type=str, default=Defaults.config_yml,
|
|
208
|
+
help=f'YAML filename to use for configuration (default {Defaults.config_yml})')
|
|
204
209
|
return parser
|
|
205
210
|
|
|
206
211
|
def get_argparser_short_help() -> str:
|
|
@@ -213,6 +218,8 @@ def get_eda_config(args:list, quiet=False) -> (dict, list):
|
|
|
213
218
|
|
|
214
219
|
Handles args for:
|
|
215
220
|
--config-yml=<YAMLFILE>
|
|
221
|
+
|
|
222
|
+
This will merge the result with the default config (if overriden)
|
|
216
223
|
'''
|
|
217
224
|
|
|
218
225
|
parser = get_argparser()
|
|
@@ -237,5 +244,7 @@ def get_eda_config(args:list, quiet=False) -> (dict, list):
|
|
|
237
244
|
else:
|
|
238
245
|
config = None
|
|
239
246
|
|
|
247
|
+
if parsed.config_yml != Defaults.config_yml:
|
|
248
|
+
config = get_config_merged_with_defaults(config)
|
|
240
249
|
|
|
241
250
|
return config, unparsed
|
opencos/eda_config_defaults.yml
CHANGED
|
@@ -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
|
|
opencos/eda_config_reduced.yml
CHANGED
|
@@ -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 \
|
opencos/eda_extract_targets.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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.
|
|
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.
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
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
|
|
29
|
-
self.error('"invio
|
|
26
|
+
if not spec:
|
|
27
|
+
self.error('"invio" package not in python env')
|
|
28
|
+
|
|
30
29
|
|
|
31
30
|
return super().get_versions()
|
|
32
31
|
|
opencos/tools/invio_yosys.py
CHANGED
|
@@ -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
|
|
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
|
|
30
|
-
self.error('"invio
|
|
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(
|
|
78
|
-
yosys_v_path = os.path.join(
|
|
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.
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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/slang_yosys.py
CHANGED
|
@@ -8,8 +8,7 @@ Contains classes for ToolSlangYosys, CommandSynthSlangYosys
|
|
|
8
8
|
import os
|
|
9
9
|
|
|
10
10
|
from opencos import util
|
|
11
|
-
from opencos.
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
opencos/tools/yosys.py
CHANGED
|
@@ -5,6 +5,7 @@ Contains classes for ToolYosys
|
|
|
5
5
|
|
|
6
6
|
# pylint: disable=R0801 # (calling functions with same arguments)
|
|
7
7
|
|
|
8
|
+
import os
|
|
8
9
|
import shutil
|
|
9
10
|
import subprocess
|
|
10
11
|
|
|
@@ -84,15 +85,44 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
84
85
|
ToolYosys.__init__(self, config=self.config)
|
|
85
86
|
|
|
86
87
|
self.args.update({
|
|
88
|
+
'sta': False,
|
|
89
|
+
'liberty-file': '',
|
|
90
|
+
'sdc-file': '',
|
|
87
91
|
'yosys-synth': 'synth', # synth_xilinx, synth_altera, etc (see: yosys help)
|
|
88
92
|
'yosys-pre-synth': ['prep', 'proc'], # command run in yosys prior to yosys-synth.
|
|
89
93
|
'yosys-blackbox': [], # list of modules that yosys will blackbox.
|
|
90
94
|
})
|
|
95
|
+
self.args_help.update({
|
|
96
|
+
'sta': 'After running Yosys, run "sta" with --liberty-file.' \
|
|
97
|
+
+ ' sta can be installed via: https://github.com/The-OpenROAD-Project/OpenSTA',
|
|
98
|
+
'sdc-file': '.sdc file to use with --sta, if not present will use auto constraints',
|
|
99
|
+
'liberty-file': 'Single liberty file for synthesis and sta,' \
|
|
100
|
+
+ ' for example: github/OpenSTA/examples/nangate45_slow.lib.gz',
|
|
101
|
+
'yosys-synth': 'The synth command provided to Yosys, see: yosys help.',
|
|
102
|
+
'yosys-pre-synth': 'Yosys commands performed prior to running "synth"' \
|
|
103
|
+
+ ' (or eda arg value for --yosys-synth)',
|
|
104
|
+
'yosys-blackbox': 'List of modules that yosys will blackbox, likely will need these' \
|
|
105
|
+
+ ' in Verilog-2001 for yosys to read outside of slang and synth',
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
self.yosys_out_dir = ''
|
|
109
|
+
self.yosys_v_path = ''
|
|
110
|
+
self.full_work_dir = ''
|
|
111
|
+
self.blackbox_list = []
|
|
91
112
|
|
|
92
113
|
def do_it(self) -> None:
|
|
93
114
|
self.set_tool_defines()
|
|
94
115
|
self.write_eda_config_and_args()
|
|
95
116
|
|
|
117
|
+
# Set up some dirs and filenames.
|
|
118
|
+
self.full_work_dir = self.args.get('work-dir', '')
|
|
119
|
+
if not self.full_work_dir:
|
|
120
|
+
self.error(f'work_dir={self.full_work_dir} is not set')
|
|
121
|
+
self.full_work_dir = os.path.abspath(self.full_work_dir)
|
|
122
|
+
self.yosys_out_dir = os.path.join(self.full_work_dir, 'yosys')
|
|
123
|
+
util.safe_mkdir(self.yosys_out_dir)
|
|
124
|
+
self.yosys_v_path = os.path.join(self.yosys_out_dir, f'{self.args["top"]}.v')
|
|
125
|
+
|
|
96
126
|
if self.is_export_enabled():
|
|
97
127
|
self.do_export()
|
|
98
128
|
return
|
|
@@ -102,3 +132,108 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
102
132
|
def write_and_run_yosys_f_files(self, **kwargs) -> None:
|
|
103
133
|
'''Derived classes must define, to run remainder of do_it() steps'''
|
|
104
134
|
raise NotImplementedError
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def create_yosys_synth_f(self) -> util.ShellCommandList:
|
|
138
|
+
'''Derived classes may define, if they wish to get a list of yosys commands'''
|
|
139
|
+
return util.ShellCommandList([])
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def get_synth_command_lines(self) -> list:
|
|
143
|
+
'''Common yosys tcl after all blackbox and read_verilog commands'''
|
|
144
|
+
|
|
145
|
+
lines = []
|
|
146
|
+
lines += self.args.get('yosys-pre-synth', [])
|
|
147
|
+
|
|
148
|
+
synth_command = self.args.get('yosys-synth', 'synth')
|
|
149
|
+
if self.args['flatten-all']:
|
|
150
|
+
synth_command += ' -flatten'
|
|
151
|
+
|
|
152
|
+
lines.append(synth_command)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# TODO(drew): I need a blackbox flow here? Or a memory_libmap?
|
|
156
|
+
# --> https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/memory_libmap.html
|
|
157
|
+
# TODO(drew): can I run multiple liberty files?
|
|
158
|
+
if self.args['liberty-file']:
|
|
159
|
+
lines += [
|
|
160
|
+
'dfflibmap -liberty ' + self.args['liberty-file'],
|
|
161
|
+
#'memory_libmap -lib ' + self.args['liberty-file'], # Has to be unzipped?
|
|
162
|
+
'abc -liberty ' + self.args['liberty-file'],
|
|
163
|
+
]
|
|
164
|
+
lines += [
|
|
165
|
+
'opt_clean',
|
|
166
|
+
f'write_verilog {self.yosys_v_path}',
|
|
167
|
+
f'write_json {self.yosys_v_path}.json',
|
|
168
|
+
]
|
|
169
|
+
return lines
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def create_sta_f(self) -> util.ShellCommandList:
|
|
173
|
+
'''Returns command list, for running 'sta' on sta.f'''
|
|
174
|
+
|
|
175
|
+
if not self.args['sta']:
|
|
176
|
+
return []
|
|
177
|
+
|
|
178
|
+
if not self.args['liberty-file']:
|
|
179
|
+
self.error('--sta is set, but need to also set --liberty-file=<file>')
|
|
180
|
+
|
|
181
|
+
if self.args['sdc-file']:
|
|
182
|
+
if not os.path.exists(self.args['sdc-file']):
|
|
183
|
+
self.error(f'--sdc-file={self.args["sdc-file"]} file does not exist')
|
|
184
|
+
|
|
185
|
+
if not self.sta_exe:
|
|
186
|
+
self.error(f'--sta is set, but "sta" was not found in PATH, see: {self._URL}')
|
|
187
|
+
|
|
188
|
+
sta_command_list = util.ShellCommandList(
|
|
189
|
+
[ self.sta_exe, '-no_init', '-exit', 'sta.f' ],
|
|
190
|
+
tee_fpath = 'sta.log'
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Need to create sta.f:
|
|
194
|
+
if self.args['sdc-file']:
|
|
195
|
+
sdc_path = self.args['sdc-file']
|
|
196
|
+
else:
|
|
197
|
+
# Need to create sdc.f:
|
|
198
|
+
sdc_path = 'sdc.f'
|
|
199
|
+
self.create_sdc_f()
|
|
200
|
+
|
|
201
|
+
with open(os.path.join(self.args['work-dir'], 'sta.f'), 'w',
|
|
202
|
+
encoding='utf-8') as f:
|
|
203
|
+
lines = [
|
|
204
|
+
'read_liberty ' + self.args['liberty-file'],
|
|
205
|
+
'read_verilog ' + self.yosys_v_path,
|
|
206
|
+
'link_design ' + self.args['top'],
|
|
207
|
+
'read_sdc ' + sdc_path,
|
|
208
|
+
'report_checks',
|
|
209
|
+
]
|
|
210
|
+
f.write('\n'.join(lines))
|
|
211
|
+
|
|
212
|
+
return util.ShellCommandList(
|
|
213
|
+
sta_command_list,
|
|
214
|
+
tee_fpath = 'sta.log'
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def create_sdc_f(self) -> None:
|
|
219
|
+
'''Returns None, creates sdc.f'''
|
|
220
|
+
|
|
221
|
+
if self.args['sdc-file']:
|
|
222
|
+
# already exists from args, return b/c nothing to create.
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
with open(os.path.join(self.args['work-dir'], 'sdc.f'), 'w',
|
|
226
|
+
encoding='utf-8') as f:
|
|
227
|
+
clock_name = self.args['clock-name']
|
|
228
|
+
period = self.args['clock-ns']
|
|
229
|
+
name_not_equal_clocks_str = f'NAME !~ "{clock_name}"'
|
|
230
|
+
lines = [
|
|
231
|
+
f'create_clock -add -name {clock_name} -period {period} [get_ports ' \
|
|
232
|
+
+ '{' + clock_name + '}];',
|
|
233
|
+
f'set_input_delay -max {self.args["idelay-ns"]} -clock {clock_name}' \
|
|
234
|
+
+ ' [get_ports * -filter {DIRECTION == IN && ' \
|
|
235
|
+
+ name_not_equal_clocks_str + '}];',
|
|
236
|
+
f'set_output_delay -max {self.args["odelay-ns"]} -clock {clock_name}' \
|
|
237
|
+
+ ' [get_ports * -filter {DIRECTION == OUT}];',
|
|
238
|
+
]
|
|
239
|
+
f.write('\n'.join(lines))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.38
|
|
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
|
|
@@ -3,25 +3,25 @@ opencos/_version.py,sha256=qN7iBoOv-v4tEZz-Pu9sVUJwefshJOsgdaddn8HcHio,510
|
|
|
3
3
|
opencos/_waves_pkg.sv,sha256=1lbhQOVGc3t_R8czYjP40hssP0I3FlZOpHTkI7yKFbI,1251
|
|
4
4
|
opencos/deps_helpers.py,sha256=Pgo3dO_QBHzGB0lE2B0uf2vWWDy3dSDN0pvW-eA6ocs,56939
|
|
5
5
|
opencos/deps_schema.py,sha256=MhytzXwp071F14RwxqHt78ak8Qruoe4FeK5XSzkO2f0,14658
|
|
6
|
-
opencos/eda.py,sha256=
|
|
7
|
-
opencos/eda_base.py,sha256=
|
|
8
|
-
opencos/eda_config.py,sha256=
|
|
9
|
-
opencos/eda_config_defaults.yml,sha256=
|
|
6
|
+
opencos/eda.py,sha256=k0_7ppBBPFsQ8Jd0mJGOnc6llUNo2hryHwx8DZ_B_jU,18832
|
|
7
|
+
opencos/eda_base.py,sha256=8kDrKM5YpwSmSqnSIItiV6R9FDr5QjraiEF3PeXe7Lw,77580
|
|
8
|
+
opencos/eda_config.py,sha256=FVp-dg9IVq78LZoh43kFYo9WXKfFxsMQMo6JGulEbEM,8818
|
|
9
|
+
opencos/eda_config_defaults.yml,sha256=0tqs4paxCYZJshb2WW2GfaZyeh_l9ZUKWMh8hh17AWk,10235
|
|
10
10
|
opencos/eda_config_max_verilator_waivers.yml,sha256=lTAU4IOEbUWVlPzuer1YYhIyxpPINeA4EJqcRIT-Ymk,840
|
|
11
|
-
opencos/eda_config_reduced.yml,sha256=
|
|
12
|
-
opencos/eda_deps_bash_completion.bash,sha256=
|
|
13
|
-
opencos/eda_extract_targets.py,sha256=
|
|
11
|
+
opencos/eda_config_reduced.yml,sha256=cQ9jY4J7EvAbeHTiP6bvpDSVJAYiitjLZPSxxLKIEbk,1440
|
|
12
|
+
opencos/eda_deps_bash_completion.bash,sha256=jMkQKY82HBgOnQeMdA1hMrXguRFtB52SMBxUemKovL4,1958
|
|
13
|
+
opencos/eda_extract_targets.py,sha256=LLf8pGia0HxqXQFRck0E990EchbEdiFTC1fQyA8FZqs,4101
|
|
14
14
|
opencos/eda_tool_helper.py,sha256=MxNd_ImyA13DZbzMol1R5H8tJZddJfqyDgFVR2ad374,1666
|
|
15
15
|
opencos/export_helper.py,sha256=2SfzHM3m6b5Wh-OMgRWv5I_A95MHIYBn8-H_P3YC7ZQ,19680
|
|
16
16
|
opencos/export_json_convert.py,sha256=KsP1ESmSWs8ouecDC5ikuwOFZNJtLjmiYOvYLeN5UZU,3768
|
|
17
|
-
opencos/files.py,sha256=
|
|
17
|
+
opencos/files.py,sha256=z7HYk5j7cMyjK8e25xzCyyUzOnj9iZt9IpGJibbbh-U,1495
|
|
18
18
|
opencos/names.py,sha256=LMhAE5UH5LEy4zqHp3rOe6tP26i_Dka6JOJzKMo_bkg,1201
|
|
19
19
|
opencos/oc_cli.py,sha256=kj2OXvgxli2WPj4MQ4zTBb36eFtsP2gsqDdeNeWGL4E,132108
|
|
20
20
|
opencos/pcie.py,sha256=VUJljaZJYgScAAx5yn7F6GoA8K9eTcw24otYZbkMpYs,3035
|
|
21
21
|
opencos/peakrdl_cleanup.py,sha256=vLhSOVs6cEzsi_PwAP4pSXu5_ZMZjDvfK_WmHDLbDac,486
|
|
22
22
|
opencos/seed.py,sha256=8TA2uXhBuT_lOaQdAKqdReYvfBWi_KuyQCFJzA2rOVM,549
|
|
23
23
|
opencos/util.py,sha256=3rADW0tUzq69wdHsa2GB060N1jCAK2Dk0NLx6N6BMcc,27861
|
|
24
|
-
opencos/commands/__init__.py,sha256=
|
|
24
|
+
opencos/commands/__init__.py,sha256=d-8heMkBjjm6_yeduZgUv34lPfHVpj9MWP1ifpdjJws,916
|
|
25
25
|
opencos/commands/build.py,sha256=jI5ul53qfwn6X-yfSdSQIcLBhGtzZUk7r_wKBBmKJI0,1425
|
|
26
26
|
opencos/commands/elab.py,sha256=m6Gk03wSzX8UkcmReooK7turF7LpqO0IcdOZwJ8XiyI,1596
|
|
27
27
|
opencos/commands/export.py,sha256=uGDI5_lUhyNB54gFjm9cWv9g_3waEOJN4wOC01oFlCY,3535
|
|
@@ -32,15 +32,16 @@ opencos/commands/proj.py,sha256=MdHTOtQYG93_gT97dWuSyAgUxX2vi9FRhL0dtc-rM98,1096
|
|
|
32
32
|
opencos/commands/sim.py,sha256=phATz_wR0BAH6B_IJ4zyzg_Hptp5hSEOe_-9NLaL_bY,14058
|
|
33
33
|
opencos/commands/sweep.py,sha256=L4AYF3vQHR-fi0871f1CwrD0y4tydrsNpWSDjVf1xIA,8719
|
|
34
34
|
opencos/commands/synth.py,sha256=quB-HWS4LKYTiFBHiYarQi4pMnRmt12wQTZpi14VvlE,4355
|
|
35
|
+
opencos/commands/targets.py,sha256=_jRNhm2Fqj0fmMvTw6Ba39DCsRHf_r_uZCy_R064kpA,1472
|
|
35
36
|
opencos/commands/upload.py,sha256=nlb4nlxrDCQPcabEmH3nP19g4PFILDqFDab4LwJ95Z4,796
|
|
36
37
|
opencos/commands/waves.py,sha256=SRfjfsqhuszXHylQrgqYiUT3a5CQs9doxJQzuV4Ae0w,7055
|
|
37
38
|
opencos/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
39
|
opencos/tests/custom_config.yml,sha256=TRoVM9ZFKPOA_8JmlpzaMhnGO1txmaD14N_8P1oqzew,257
|
|
39
|
-
opencos/tests/helpers.py,sha256=
|
|
40
|
+
opencos/tests/helpers.py,sha256=zzQQP8ZeNUwrvJRQVlpTnvz9yxFG0Jfuss50ZPjxa-c,8240
|
|
40
41
|
opencos/tests/test_build.py,sha256=FQAxOpLVQShAHD_L5rqJctPeSAoqoOCNFI0RXflLuY0,387
|
|
41
42
|
opencos/tests/test_deps_helpers.py,sha256=_nJSgLN6WVlMKqu6sCr29gjQyN3Jj-dVk8Ac64ygpJs,5928
|
|
42
43
|
opencos/tests/test_deps_schema.py,sha256=mWTWI4wriGXC8UAnaeq_MIvWJOvf08-fPUqUgELptQ4,896
|
|
43
|
-
opencos/tests/test_eda.py,sha256=
|
|
44
|
+
opencos/tests/test_eda.py,sha256=eraWvyJJHrlq4CVoeWakYckRG8RRUYtecJRzlcXX45Q,38545
|
|
44
45
|
opencos/tests/test_eda_elab.py,sha256=75bJpOaoO8rn1FXFxiE4KSu5FdjZP1IbW6SyTCjM_ao,2553
|
|
45
46
|
opencos/tests/test_eda_synth.py,sha256=C_1LzblTuK_lHFv_Hh8v3DKUN4hGfxoChYR77GricX4,2871
|
|
46
47
|
opencos/tests/test_oc_cli.py,sha256=-ZmwVX_CPBXCGT9hXIBEr_XUSIGG2eky89YpSJIbRAg,731
|
|
@@ -53,23 +54,23 @@ opencos/tests/deps_files/non_sv_reqs/DEPS.yml,sha256=VZkahO1AKhD9GUV5lK8VwUONEi5
|
|
|
53
54
|
opencos/tests/deps_files/tags_with_tools/DEPS.yml,sha256=-5U1qfJElgpVhmkLEu3lYuvDYva8kDlt6JOdB9jidmc,1377
|
|
54
55
|
opencos/tests/deps_files/test_err_fatal/DEPS.yml,sha256=GnXIUJvshQWR9PlYxX67T53ejf5KhDbtD8sUJB4Rwd0,95
|
|
55
56
|
opencos/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
|
-
opencos/tools/invio.py,sha256=
|
|
57
|
+
opencos/tools/invio.py,sha256=q9E9n6xsozDfar-1rLvJEZbCpPb_bQEy6WKEI3KS3dk,3163
|
|
57
58
|
opencos/tools/invio_helpers.py,sha256=1au4CYmV5aC7DHjaZBNemydH6Eq0i-Yt5L3HyKfQOfY,7638
|
|
58
|
-
opencos/tools/invio_yosys.py,sha256=
|
|
59
|
+
opencos/tools/invio_yosys.py,sha256=4zWBeFKXHSyb5WSnf6ZpVG2UwoKF0SC-00I1_VqgXZM,6016
|
|
59
60
|
opencos/tools/iverilog.py,sha256=1SmkJAtG096ozIY6N19UtpD-YT1UKJAcMLJ9blfraP0,6413
|
|
60
61
|
opencos/tools/modelsim_ase.py,sha256=x5xFWBNaln2lVLixN0Od0uNaLKN_Bt1q6a91QmhKoNA,13162
|
|
61
62
|
opencos/tools/questa.py,sha256=AX_3USyf6eMcssH4b-8WLbCzz-cXYnQzlHvCyL9C7Og,7505
|
|
62
63
|
opencos/tools/slang.py,sha256=74EDAAnN7mrrYxgxaPDaoRJZK7Se9B_HsW8Ioi2Nw44,7425
|
|
63
|
-
opencos/tools/slang_yosys.py,sha256=
|
|
64
|
+
opencos/tools/slang_yosys.py,sha256=mw4AfutGjKyCj7NLrHDy2j3p0XC2H7uuBf9RkVQJYoQ,9856
|
|
64
65
|
opencos/tools/surelog.py,sha256=JOMs8SqnzJ_ZL5mEdyyn3Z1r1Kc8hfbV3Pnen1YzxWA,4980
|
|
65
66
|
opencos/tools/tabbycad_yosys.py,sha256=h9kkAi479cZzYfb4R9WBNY_JmR6BgVFj4s3VShnGpoA,7813
|
|
66
67
|
opencos/tools/verilator.py,sha256=0ZHAkkUqnsM1A4B8-u6tff3lhl-cgfDUx-Dq7DaRwkI,18080
|
|
67
68
|
opencos/tools/vivado.py,sha256=cL5IZdudqquddvZqHQGDVmaHSxgBZsMUmAq18q8AgoM,39134
|
|
68
|
-
opencos/tools/yosys.py,sha256=
|
|
69
|
-
opencos_eda-0.2.
|
|
70
|
-
opencos_eda-0.2.
|
|
71
|
-
opencos_eda-0.2.
|
|
72
|
-
opencos_eda-0.2.
|
|
73
|
-
opencos_eda-0.2.
|
|
74
|
-
opencos_eda-0.2.
|
|
75
|
-
opencos_eda-0.2.
|
|
69
|
+
opencos/tools/yosys.py,sha256=aZnRFbsODYRe4BHbfxl6vfWeEP7WJYJk50gCZcn8Fu0,8902
|
|
70
|
+
opencos_eda-0.2.38.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
71
|
+
opencos_eda-0.2.38.dist-info/licenses/LICENSE.spdx,sha256=8gn1610RMP6eFgT3Hm6q9VKXt0RvdTItL_oxMo72jII,189
|
|
72
|
+
opencos_eda-0.2.38.dist-info/METADATA,sha256=kKhYeLRFFBsjoHaLMNW-xyGGbQejy0hEnW00rsC6puQ,604
|
|
73
|
+
opencos_eda-0.2.38.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
74
|
+
opencos_eda-0.2.38.dist-info/entry_points.txt,sha256=V8OE1lySAFcFQpDNJuVxVZteeSmDH-joLMhGvrxrvmg,164
|
|
75
|
+
opencos_eda-0.2.38.dist-info/top_level.txt,sha256=J4JDP-LpRyJqPNeh9bSjx6yrLz2Mk0h6un6YLmtqql4,8
|
|
76
|
+
opencos_eda-0.2.38.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|