opencos-eda 0.2.44__py3-none-any.whl → 0.2.46__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 +4 -0
- opencos/commands/lec.py +103 -0
- opencos/commands/shell.py +202 -0
- opencos/commands/sim.py +1 -1
- opencos/deps_helpers.py +15 -12
- opencos/deps_schema.py +3 -0
- opencos/eda.py +2 -0
- opencos/eda_base.py +32 -15
- opencos/eda_config_defaults.yml +17 -5
- opencos/eda_extract_targets.py +13 -3
- opencos/tests/helpers.py +2 -1
- opencos/tests/test_deps_schema.py +3 -1
- opencos/tests/test_eda.py +19 -9
- opencos/tools/invio_yosys.py +7 -7
- opencos/tools/slang_yosys.py +29 -38
- opencos/tools/tabbycad_yosys.py +1 -1
- opencos/tools/vivado.py +8 -7
- opencos/tools/yosys.py +433 -12
- opencos/util.py +14 -6
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.46.dist-info}/METADATA +1 -1
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.46.dist-info}/RECORD +26 -24
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.46.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.46.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.46.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.46.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.46.dist-info}/top_level.txt +0 -0
opencos/tests/test_eda.py
CHANGED
|
@@ -692,14 +692,22 @@ class TestDepsReqs:
|
|
|
692
692
|
assert rc != 0
|
|
693
693
|
|
|
694
694
|
|
|
695
|
-
@pytest.mark.
|
|
696
|
-
def test_deps_command_order():
|
|
695
|
+
@pytest.mark.parametrize("command", ['sim', 'shell'])
|
|
696
|
+
def test_deps_command_order(command):
|
|
697
697
|
'''Test for various "commands" within a DEPS target. This test checks that command
|
|
698
698
|
order is preserved in the top-to-bottom deps order, meaning that eda.py has to collect
|
|
699
699
|
all commands deps order, and then execute them in that order.'''
|
|
700
700
|
|
|
701
701
|
chdir_remove_work_dir('deps_files/command_order')
|
|
702
|
-
|
|
702
|
+
if command == 'sim' and not can_run_eda_sim():
|
|
703
|
+
pytest.skip(f'sim skipped, {can_run_eda_sim()=}')
|
|
704
|
+
return # skip/pass
|
|
705
|
+
|
|
706
|
+
if command == 'shell':
|
|
707
|
+
cmd_list = 'shell target_test'.split()
|
|
708
|
+
else:
|
|
709
|
+
cmd_list = 'sim --stop-before-compile target_test'.split()
|
|
710
|
+
|
|
703
711
|
with open('eda.log', 'w', encoding='utf-8') as f:
|
|
704
712
|
with redirect_stdout(f):
|
|
705
713
|
with redirect_stderr(f):
|
|
@@ -730,14 +738,16 @@ def test_deps_command_order():
|
|
|
730
738
|
# Added check, we redirected to create eda.log earlier to confirm the targets worked,
|
|
731
739
|
# but as a general eda.py check, all shell commands should create their own
|
|
732
740
|
# {target}__shell_0.log file:
|
|
733
|
-
work_dir = os.path.join(
|
|
741
|
+
work_dir = os.path.join(
|
|
742
|
+
THISPATH, 'deps_files', 'command_order', 'eda.work', f'target_test.{command}'
|
|
743
|
+
)
|
|
734
744
|
with open(os.path.join(work_dir, 'target_echo_hi__shell_0.log'), encoding='utf-8') as f:
|
|
735
745
|
text = ''.join(f.readlines()).strip()
|
|
736
|
-
assert text
|
|
746
|
+
assert text in ['hi', '"hi"', '\\"hi\\"']
|
|
737
747
|
# Added check, one of the targets uses a custom 'tee' file name, instead of the default log.
|
|
738
748
|
with open(os.path.join(work_dir, 'custom_tee_echo_bye.log'), encoding='utf-8') as f:
|
|
739
749
|
text = ''.join(f.readlines()).strip()
|
|
740
|
-
assert text
|
|
750
|
+
assert text in ['bye', '"bye"', '\\"bye\\"']
|
|
741
751
|
|
|
742
752
|
|
|
743
753
|
@pytest.mark.skipif('verilator' not in tools_loaded, reason="requires verilator")
|
|
@@ -896,9 +906,9 @@ class TestDepsTags(Helpers):
|
|
|
896
906
|
# b/c that should only apply in 'verilator' for this target.)
|
|
897
907
|
exec_lines = self.get_log_lines_with('exec: ', logfile=logfile)
|
|
898
908
|
assert len(exec_lines) == 3
|
|
899
|
-
assert 'xvlog
|
|
900
|
-
assert 'xelab
|
|
901
|
-
assert 'xsim
|
|
909
|
+
assert 'xvlog' in exec_lines[0]
|
|
910
|
+
assert 'xelab' in exec_lines[1]
|
|
911
|
+
assert 'xsim' in exec_lines[2]
|
|
902
912
|
assert not self.is_in_log('--lint-only', logfile=logfile)
|
|
903
913
|
|
|
904
914
|
|
opencos/tools/invio_yosys.py
CHANGED
|
@@ -51,7 +51,7 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
|
|
|
51
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
|
|
54
|
+
def write_and_run_yosys_f_files(self) -> None:
|
|
55
55
|
|
|
56
56
|
# Use helper module for Invio/Verific to save out Verilog-2001 from our
|
|
57
57
|
# Verilog + SystemVerilog + VHDL file lists.
|
|
@@ -104,7 +104,7 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
|
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
# Optinally create and run a sta.f:
|
|
107
|
-
|
|
107
|
+
sta_command_lists = self.create_sta_f() # [] or [util.ShellCommandList]
|
|
108
108
|
|
|
109
109
|
# We create a run_yosys.sh wrapping these scripts, but we do not run this one.
|
|
110
110
|
util.write_shell_command_file(
|
|
@@ -122,8 +122,7 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
|
|
|
122
122
|
# Gives us bash commands with tee and pipstatus:
|
|
123
123
|
invio_command_list,
|
|
124
124
|
synth_command_list,
|
|
125
|
-
|
|
126
|
-
],
|
|
125
|
+
] + sta_command_lists,
|
|
127
126
|
)
|
|
128
127
|
|
|
129
128
|
# Do not run this if args['stop-before-compile'] is True
|
|
@@ -135,9 +134,10 @@ class CommandSynthInvioYosys(CommonSynthYosys, ToolInvioYosys):
|
|
|
135
134
|
self.exec( work_dir=work_dir, command_list=synth_command_list,
|
|
136
135
|
tee_fpath=synth_command_list.tee_fpath )
|
|
137
136
|
|
|
138
|
-
|
|
139
|
-
self.
|
|
140
|
-
|
|
137
|
+
for x in sta_command_lists:
|
|
138
|
+
if self.args['sta'] and x:
|
|
139
|
+
self.exec(work_dir=self.full_work_dir, command_list=x,
|
|
140
|
+
tee_fpath=x.tee_fpath)
|
|
141
141
|
|
|
142
142
|
if self.status == 0:
|
|
143
143
|
util.info(f'yosys: wrote verilog to {self.yosys_v_path}')
|
opencos/tools/slang_yosys.py
CHANGED
|
@@ -8,7 +8,7 @@ Contains classes for ToolSlangYosys, CommandSynthSlangYosys
|
|
|
8
8
|
import os
|
|
9
9
|
|
|
10
10
|
from opencos import util
|
|
11
|
-
from opencos.tools.yosys import ToolYosys, CommonSynthYosys
|
|
11
|
+
from opencos.tools.yosys import ToolYosys, CommonSynthYosys, CommandLecYosys
|
|
12
12
|
|
|
13
13
|
class ToolSlangYosys(ToolYosys):
|
|
14
14
|
'''Uses slang.so in yosys plugins directory, called via yosys > plugin -i slang'''
|
|
@@ -37,7 +37,7 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
37
37
|
self.slang_out_dir = ''
|
|
38
38
|
self.slang_v_path = ''
|
|
39
39
|
|
|
40
|
-
def write_and_run_yosys_f_files(self
|
|
40
|
+
def write_and_run_yosys_f_files(self) -> None:
|
|
41
41
|
'''
|
|
42
42
|
1. Creates and runs: yosys.slang.f
|
|
43
43
|
-- should create post_slang_ls.txt
|
|
@@ -54,7 +54,7 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
54
54
|
self.blackbox_list += self.args.get('synth-blackbox', [])
|
|
55
55
|
util.debug(f'slang_yosys: {self.blackbox_list=}')
|
|
56
56
|
|
|
57
|
-
# create {work_dir} /
|
|
57
|
+
# create {work_dir} / slang
|
|
58
58
|
self.slang_out_dir = os.path.join(self.full_work_dir, 'slang')
|
|
59
59
|
util.safe_mkdir(self.slang_out_dir)
|
|
60
60
|
|
|
@@ -62,13 +62,13 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
62
62
|
|
|
63
63
|
# Run our created yosys.slang.f script
|
|
64
64
|
# Note - this will always run, even if --stop-before-compile is set.
|
|
65
|
-
slang_command_list = self.
|
|
65
|
+
slang_command_list = self._create_and_run_yosys_slang_f() # util.ShellCommandList
|
|
66
66
|
|
|
67
67
|
# Create and run yosys.synth.f
|
|
68
68
|
synth_command_list = self.create_yosys_synth_f() # util.ShellCommandList
|
|
69
69
|
|
|
70
70
|
# Optinally create and run a sta.f:
|
|
71
|
-
|
|
71
|
+
sta_command_lists = self.create_sta_f() # [] or [util.ShellCommandList]
|
|
72
72
|
|
|
73
73
|
# We create a run_yosys.sh wrapping these scripts, but we do not run this one.
|
|
74
74
|
util.write_shell_command_file(
|
|
@@ -78,8 +78,7 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
78
78
|
# Gives us bash commands with tee and pipstatus:
|
|
79
79
|
slang_command_list,
|
|
80
80
|
synth_command_list,
|
|
81
|
-
|
|
82
|
-
],
|
|
81
|
+
] + sta_command_lists,
|
|
83
82
|
)
|
|
84
83
|
|
|
85
84
|
# Do not run this if args['stop-before-compile'] is True
|
|
@@ -92,9 +91,10 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
92
91
|
self.exec(work_dir=self.full_work_dir, command_list=synth_command_list,
|
|
93
92
|
tee_fpath=synth_command_list.tee_fpath)
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
self.
|
|
97
|
-
|
|
94
|
+
for x in sta_command_lists:
|
|
95
|
+
if self.args['sta'] and x:
|
|
96
|
+
self.exec(work_dir=self.full_work_dir, command_list=x,
|
|
97
|
+
tee_fpath=x.tee_fpath)
|
|
98
98
|
|
|
99
99
|
if self.status == 0:
|
|
100
100
|
util.info(f'yosys: wrote verilog to {self.yosys_v_path}')
|
|
@@ -108,36 +108,13 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
108
108
|
'--best-effort-hierarchy',
|
|
109
109
|
]
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
if not name:
|
|
113
|
-
continue
|
|
114
|
-
if name in ['SIMULATION']:
|
|
115
|
-
continue
|
|
116
|
-
|
|
117
|
-
if value is None:
|
|
118
|
-
read_slang_cmd.append(f'--define-macro {name}')
|
|
119
|
-
else:
|
|
120
|
-
read_slang_cmd.append(f'--define-macro {name}={value}')
|
|
121
|
-
|
|
122
|
-
# We must define SYNTHESIS for oclib_defines.vh to work correctly.
|
|
123
|
-
if 'SYNTHESIS' not in self.defines:
|
|
124
|
-
read_slang_cmd.append('--define-macro SYNTHESIS')
|
|
125
|
-
|
|
126
|
-
for path in self.incdirs:
|
|
127
|
-
read_slang_cmd.append(f'-I {path}')
|
|
128
|
-
|
|
129
|
-
for path in self.files_v:
|
|
130
|
-
read_slang_cmd.append(path)
|
|
131
|
-
|
|
132
|
-
for path in self.files_sv:
|
|
133
|
-
read_slang_cmd.append(path)
|
|
134
|
-
|
|
111
|
+
read_slang_cmd += self.get_yosys_read_verilog_defines_incdirs_files()
|
|
135
112
|
read_slang_cmd.append(f'--top {self.args["top"]}')
|
|
136
113
|
return ' '.join(read_slang_cmd)
|
|
137
114
|
|
|
138
115
|
|
|
139
|
-
def
|
|
140
|
-
'''Returns the util.ShellCommandList for: yosys --scriptfile yosys.slang.f'''
|
|
116
|
+
def _create_and_run_yosys_slang_f(self) -> util.ShellCommandList:
|
|
117
|
+
'''Runs, and Returns the util.ShellCommandList for: yosys --scriptfile yosys.slang.f'''
|
|
141
118
|
|
|
142
119
|
script_slang_lines = [
|
|
143
120
|
'plugin -i slang'
|
|
@@ -181,7 +158,7 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
181
158
|
)
|
|
182
159
|
return slang_command_list
|
|
183
160
|
|
|
184
|
-
def
|
|
161
|
+
def get_yosys_blackbox_list(self) -> list:
|
|
185
162
|
'''Based on the results in post_slang_ls.txt, create blackbox commands for
|
|
186
163
|
|
|
187
164
|
yosys.synth.f script. Uses self.blackbox_list.
|
|
@@ -206,12 +183,14 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
206
183
|
return yosys_blackbox_list
|
|
207
184
|
|
|
208
185
|
def create_yosys_synth_f(self) -> util.ShellCommandList:
|
|
186
|
+
'''Overriden from CommonSynthYosys'''
|
|
187
|
+
|
|
209
188
|
# Create yosys.synth.f
|
|
210
189
|
yosys_synth_f_path = os.path.join(self.full_work_dir, 'yosys.synth.f')
|
|
211
190
|
|
|
212
191
|
# Based on the results in post_slang_ls.txt, create blackbox commands for
|
|
213
192
|
# yosys.synth.f script.
|
|
214
|
-
yosys_blackbox_list = self.
|
|
193
|
+
yosys_blackbox_list = self.get_yosys_blackbox_list()
|
|
215
194
|
|
|
216
195
|
if self.args['liberty-file'] and not os.path.exists(self.args['liberty-file']):
|
|
217
196
|
self.error(f'--liberty-file={self.args["liberty-file"]} file does not exist')
|
|
@@ -251,3 +230,15 @@ class CommandElabSlangYosys(CommandSynthSlangYosys): # pylint: disable=too-many-
|
|
|
251
230
|
'stop-before-compile': True,
|
|
252
231
|
'lint': True
|
|
253
232
|
})
|
|
233
|
+
|
|
234
|
+
class CommandLecSlangYosys(CommandLecYosys, ToolSlangYosys): # pylint: disable=too-many-ancestors
|
|
235
|
+
'''CommandHandler for: eda lec --tool=slang_yosys
|
|
236
|
+
|
|
237
|
+
All steps from CommandLecYosys are re-used, except that using ToolSlangYosys
|
|
238
|
+
instead of ToolYosys. This is necessary so the default --synth arg will
|
|
239
|
+
synthesize the two designs using slang_yosys for the tool instead of yosys.
|
|
240
|
+
'''
|
|
241
|
+
|
|
242
|
+
def __init__(self, config: dict):
|
|
243
|
+
CommandLecYosys.__init__(self, config)
|
|
244
|
+
ToolSlangYosys.__init__(self, config=self.config)
|
opencos/tools/tabbycad_yosys.py
CHANGED
|
@@ -36,7 +36,7 @@ class CommandSynthTabbyCadYosys(CommonSynthYosys, ToolTabbyCadYosys):
|
|
|
36
36
|
ToolTabbyCadYosys.__init__(self, config=self.config)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def write_and_run_yosys_f_files(self
|
|
39
|
+
def write_and_run_yosys_f_files(self) -> None:
|
|
40
40
|
'''
|
|
41
41
|
1. Creates and runs: yosys.verific.f
|
|
42
42
|
-- should create post_verific_ls.txt
|
opencos/tools/vivado.py
CHANGED
|
@@ -649,10 +649,10 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
649
649
|
eda_path = eda_base.get_eda_exec('flist')
|
|
650
650
|
command_list = [
|
|
651
651
|
eda_path, 'flist',
|
|
652
|
-
'--tool'
|
|
652
|
+
'--tool=' + self.args['tool'],
|
|
653
653
|
self.args['top-path'],
|
|
654
654
|
'--force',
|
|
655
|
-
'--out'
|
|
655
|
+
'--out=' + flist_file,
|
|
656
656
|
#'--no-emit-incdir',
|
|
657
657
|
#'--no-single-quote-define', # Needed to run in Command.exec( ... shell=False)
|
|
658
658
|
'--no-quote-define',
|
|
@@ -662,11 +662,11 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
662
662
|
'--no-equal-define',
|
|
663
663
|
'--bracket-quote-path',
|
|
664
664
|
# on --prefix- items, use shlex.quote(str) so spaces work with subprocess shell=False:
|
|
665
|
-
'--prefix-incdir'
|
|
666
|
-
'--prefix-define'
|
|
667
|
-
'--prefix-sv'
|
|
668
|
-
'--prefix-v'
|
|
669
|
-
'--prefix-vhd'
|
|
665
|
+
'--prefix-incdir=' + shlex.quote("oc_set_project_incdir "),
|
|
666
|
+
'--prefix-define=' + shlex.quote("oc_set_project_define "),
|
|
667
|
+
'--prefix-sv=' + shlex.quote("add_files -norecurse "),
|
|
668
|
+
'--prefix-v=' + shlex.quote("add_files -norecurse "),
|
|
669
|
+
'--prefix-vhd=' + shlex.quote("add_files -norecurse "),
|
|
670
670
|
]
|
|
671
671
|
for key,value in self.defines.items():
|
|
672
672
|
if value is None:
|
|
@@ -674,6 +674,7 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
674
674
|
else:
|
|
675
675
|
command_list += [ shlex.quote(f"+define+{key}={value}") ]
|
|
676
676
|
cwd = util.getcwd()
|
|
677
|
+
util.debug(f"CommandBuildVivado: {cwd=}")
|
|
677
678
|
|
|
678
679
|
|
|
679
680
|
# Write out a .sh command, but only for debug, it is not run.
|