opencos-eda 0.2.43__py3-none-any.whl → 0.2.45__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/export.py +0 -1
- opencos/commands/flist.py +4 -1
- opencos/commands/lec.py +103 -0
- opencos/commands/shell.py +202 -0
- opencos/commands/sim.py +1 -1
- opencos/deps_helpers.py +2 -0
- opencos/eda.py +6 -3
- opencos/eda_base.py +12 -4
- opencos/eda_config.py +1 -1
- opencos/eda_config_defaults.yml +22 -7
- opencos/eda_extract_targets.py +13 -3
- opencos/export_helper.py +6 -4
- opencos/files.py +1 -0
- opencos/tests/helpers.py +3 -2
- opencos/tests/test_deps_schema.py +3 -1
- opencos/tests/test_eda.py +19 -9
- opencos/tests/test_eda_synth.py +63 -2
- opencos/tools/invio_yosys.py +7 -7
- opencos/tools/iverilog.py +1 -1
- opencos/tools/riviera.py +1 -1
- opencos/tools/slang.py +1 -1
- opencos/tools/slang_yosys.py +29 -38
- opencos/tools/surelog.py +1 -1
- opencos/tools/tabbycad_yosys.py +1 -1
- opencos/tools/verilator.py +1 -1
- opencos/tools/vivado.py +30 -11
- opencos/tools/yosys.py +465 -25
- opencos/util.py +19 -12
- {opencos_eda-0.2.43.dist-info → opencos_eda-0.2.45.dist-info}/METADATA +1 -1
- {opencos_eda-0.2.43.dist-info → opencos_eda-0.2.45.dist-info}/RECORD +36 -34
- {opencos_eda-0.2.43.dist-info → opencos_eda-0.2.45.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.43.dist-info → opencos_eda-0.2.45.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.43.dist-info → opencos_eda-0.2.45.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.43.dist-info → opencos_eda-0.2.45.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.43.dist-info → opencos_eda-0.2.45.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/tests/test_eda_synth.py
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
'''pytests for: eda [multi|tools-multi] synth [args] <target(s)>'''
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import shutil
|
|
5
|
+
|
|
4
6
|
import pytest
|
|
5
7
|
|
|
6
8
|
from opencos import eda, eda_tool_helper
|
|
7
9
|
from opencos.tests import helpers
|
|
10
|
+
from opencos.tests.helpers import Helpers
|
|
8
11
|
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
THISPATH = os.path.dirname(__file__)
|
|
11
14
|
|
|
12
15
|
def chdir_remove_work_dir(relpath):
|
|
13
16
|
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
14
|
-
return helpers.chdir_remove_work_dir(
|
|
17
|
+
return helpers.chdir_remove_work_dir(THISPATH, relpath)
|
|
15
18
|
|
|
16
19
|
# Figure out what tools the system has available, without calling eda.main(..)
|
|
17
20
|
config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
|
|
@@ -75,3 +78,61 @@ class Tests:
|
|
|
75
78
|
rc = eda.main(*cmdlist)
|
|
76
79
|
print(f'{rc=}')
|
|
77
80
|
assert rc == 0
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def vivado_has_xpms() -> bool:
|
|
84
|
+
'''Returns True if Vivado is installed and has visibility to XPMs'''
|
|
85
|
+
if 'vivado' not in tools_loaded:
|
|
86
|
+
return False
|
|
87
|
+
vivado_exe = shutil.which('vivado')
|
|
88
|
+
vivado_bin_path, _ = os.path.split(vivado_exe)
|
|
89
|
+
vivado_base_path, _ = os.path.split(vivado_bin_path) # strip bin/vivado
|
|
90
|
+
|
|
91
|
+
return os.path.exists(os.path.join(vivado_base_path, 'data', 'ip', 'xpm'))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@pytest.mark.skipif(
|
|
95
|
+
'slang_yosys' not in tools_loaded, reason="requires slang_yosys for synth"
|
|
96
|
+
)
|
|
97
|
+
class TestsSlangYosys(Helpers):
|
|
98
|
+
'''Tests that require tool=slang_yosys to be available'''
|
|
99
|
+
|
|
100
|
+
def test_sdc_file(self):
|
|
101
|
+
'''Test for 'eda synth' on oclib_fifo_with_sdc
|
|
102
|
+
|
|
103
|
+
This does not use the actual .sdc file, but it also shouldn't fail with
|
|
104
|
+
that file in the 'deps' list (CommandDesign should track it correctly)
|
|
105
|
+
'''
|
|
106
|
+
chdir_remove_work_dir('deps_files/test_sdc_files')
|
|
107
|
+
cmd_str = 'synth --tool=slang_yosys oclib_fifo_with_sdc'
|
|
108
|
+
rc = self.log_it(cmd_str, use_eda_wrap=False)
|
|
109
|
+
assert rc == 0
|
|
110
|
+
|
|
111
|
+
@pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
|
|
112
|
+
@pytest.mark.skipif(not vivado_has_xpms(), reason="requires install to have XPMs")
|
|
113
|
+
class TestsVivado(Helpers):
|
|
114
|
+
'''Tests that require tool=vivado with XPMs available for synthesis'''
|
|
115
|
+
|
|
116
|
+
def test_sdc_file(self):
|
|
117
|
+
'''Test for 'eda synth' on oclib_fifo_with_sdc
|
|
118
|
+
|
|
119
|
+
And check that the .sdc file was used and not the default generated .xdc
|
|
120
|
+
file
|
|
121
|
+
'''
|
|
122
|
+
chdir_remove_work_dir('deps_files/test_sdc_files')
|
|
123
|
+
cmd_str = 'synth --tool=vivado oclib_fifo_with_sdc'
|
|
124
|
+
rc = self.log_it(cmd_str, use_eda_wrap=False)
|
|
125
|
+
assert rc == 0
|
|
126
|
+
|
|
127
|
+
# apparently this doesn't get saved in the eda.log. That's not great,
|
|
128
|
+
# but we can check the <target>.synth.log file.
|
|
129
|
+
synth_log = os.path.join(
|
|
130
|
+
THISPATH, 'deps_files', 'test_sdc_files',
|
|
131
|
+
'eda.work', 'oclib_fifo_with_sdc.synth', 'oclib_fifo.synth.log'
|
|
132
|
+
)
|
|
133
|
+
sdc_lines = self.get_log_lines_with('.sdc', logfile=synth_log)
|
|
134
|
+
assert sdc_lines
|
|
135
|
+
for sdc_line in sdc_lines:
|
|
136
|
+
assert 'oclib_fifo_vivado.sdc' in sdc_line
|
|
137
|
+
assert 'test_sdc_files' in sdc_line
|
|
138
|
+
assert 'eda.work' not in sdc_line
|
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/iverilog.py
CHANGED
|
@@ -37,7 +37,7 @@ class ToolIverilog(Tool):
|
|
|
37
37
|
iverilog_version_ret = subprocess.run(
|
|
38
38
|
[self.iverilog_exe, '-v'], capture_output=True, check=False
|
|
39
39
|
)
|
|
40
|
-
lines = iverilog_version_ret.stdout.decode("utf-8").split('\n')
|
|
40
|
+
lines = iverilog_version_ret.stdout.decode("utf-8", errors="replace").split('\n')
|
|
41
41
|
words = lines[0].split() # 'Icarus Verilog version 13.0 (devel) (s20221226-568-g62727e8b2)'
|
|
42
42
|
version = words[3]
|
|
43
43
|
util.debug(f'{iverilog_path=} {lines[0]=}')
|
opencos/tools/riviera.py
CHANGED
|
@@ -36,7 +36,7 @@ class ToolRiviera(ToolModelsimAse):
|
|
|
36
36
|
capture_output=True,
|
|
37
37
|
check=False
|
|
38
38
|
)
|
|
39
|
-
stdout = version_ret.stdout.decode('utf-8').rstrip()
|
|
39
|
+
stdout = version_ret.stdout.decode('utf-8', errors='replace').rstrip()
|
|
40
40
|
|
|
41
41
|
# Expect:
|
|
42
42
|
# Aldec, Inc. Riviera-PRO version 2025.04.139.9738 built for Linux64 on May 30, 2025
|
opencos/tools/slang.py
CHANGED
|
@@ -44,7 +44,7 @@ class ToolSlang(Tool):
|
|
|
44
44
|
capture_output=True,
|
|
45
45
|
check=False
|
|
46
46
|
)
|
|
47
|
-
stdout = version_ret.stdout.decode('utf-8')
|
|
47
|
+
stdout = version_ret.stdout.decode('utf-8', errors='replace')
|
|
48
48
|
util.debug(f'{path=} {version_ret=}')
|
|
49
49
|
words = stdout.split() # slang version 8.0.6+b4a74b00
|
|
50
50
|
if len(words) < 3:
|
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/surelog.py
CHANGED
|
@@ -33,7 +33,7 @@ class ToolSurelog(Tool):
|
|
|
33
33
|
version_ret = subprocess.run(
|
|
34
34
|
[self.surelog_exe, '--version'], capture_output=True, check=False
|
|
35
35
|
)
|
|
36
|
-
stdout = version_ret.stdout.decode('utf-8')
|
|
36
|
+
stdout = version_ret.stdout.decode('utf-8', errors='replace')
|
|
37
37
|
util.debug(f'{path=} {version_ret=}')
|
|
38
38
|
words = stdout.split() # VERSION: 1.84 (first line)
|
|
39
39
|
if len(words) < 2:
|
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/verilator.py
CHANGED
|
@@ -49,7 +49,7 @@ class ToolVerilator(Tool):
|
|
|
49
49
|
capture_output=True,
|
|
50
50
|
check=False
|
|
51
51
|
)
|
|
52
|
-
stdout = version_ret.stdout.decode('utf-8')
|
|
52
|
+
stdout = version_ret.stdout.decode('utf-8', errors='replace')
|
|
53
53
|
util.debug(f'{path=} {version_ret=}')
|
|
54
54
|
words = stdout.split() # 'Verilator 5.027 devel rev v5.026-92-g403a197e2
|
|
55
55
|
if len(words) < 1:
|
opencos/tools/vivado.py
CHANGED
|
@@ -70,7 +70,7 @@ class ToolVivado(Tool):
|
|
|
70
70
|
#try:
|
|
71
71
|
# # Get version from vivado -version, or xsim --version:
|
|
72
72
|
# vivado_ret = subprocess.run(['vivado', '-version'], capture_output=True)
|
|
73
|
-
# lines = vivado_ret.stdout.decode('utf-8').split('\n')
|
|
73
|
+
# lines = vivado_ret.stdout.decode('utf-8', errors='replace').split('\n')
|
|
74
74
|
# words = lines[0].split() # vivado v2024.2.1 (64-bit)
|
|
75
75
|
# version = words[1][1:] # 2024.2.1
|
|
76
76
|
# self._VERSION = version
|
|
@@ -388,9 +388,14 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
|
|
|
388
388
|
self.exec(self.args['work-dir'], command_list)
|
|
389
389
|
|
|
390
390
|
|
|
391
|
-
def write_tcl_file(
|
|
391
|
+
def write_tcl_file( # pylint: disable=too-many-locals,too-many-branches
|
|
392
|
+
self, tcl_file: str
|
|
393
|
+
) -> None:
|
|
392
394
|
'''Writes synthesis capable Vivado tcl file to filepath 'tcl_file'.'''
|
|
393
395
|
|
|
396
|
+
# TODO(drew): This method needs to be broken up to avoid the pylint
|
|
397
|
+
# waivers.
|
|
398
|
+
|
|
394
399
|
v = self.get_vivado_tcl_verbose_arg()
|
|
395
400
|
|
|
396
401
|
defines = ""
|
|
@@ -416,9 +421,12 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
|
|
|
416
421
|
part = self.args['part']
|
|
417
422
|
top = self.args['top']
|
|
418
423
|
|
|
424
|
+
default_xdc = False
|
|
419
425
|
if self.args['xdc'] != "":
|
|
420
|
-
default_xdc = False
|
|
421
426
|
xdc_file = os.path.abspath(self.args['xdc'])
|
|
427
|
+
elif self.files_sdc:
|
|
428
|
+
# Use files from DEPS target or command line.
|
|
429
|
+
xdc_file = ''
|
|
422
430
|
else:
|
|
423
431
|
default_xdc = True
|
|
424
432
|
xdc_file = os.path.abspath(os.path.join(self.args['work-dir'],
|
|
@@ -427,7 +435,17 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
|
|
|
427
435
|
|
|
428
436
|
tcl_lines += [
|
|
429
437
|
f"create_fileset -constrset constraints_1 {v}",
|
|
430
|
-
|
|
438
|
+
]
|
|
439
|
+
for _file in self.files_sdc:
|
|
440
|
+
# NOTE - sdc files cannot (yet) be attached to other modules.
|
|
441
|
+
tcl_lines += [
|
|
442
|
+
f"add_files -fileset constraints_1 {_file} {v}",
|
|
443
|
+
]
|
|
444
|
+
if xdc_file:
|
|
445
|
+
tcl_lines += [
|
|
446
|
+
f"add_files -fileset constraints_1 {xdc_file} {v}",
|
|
447
|
+
]
|
|
448
|
+
tcl_lines += [
|
|
431
449
|
"# FIRST PASS -- auto_detect_xpm",
|
|
432
450
|
"synth_design -rtl -rtl_skip_ip -rtl_skip_constraints -no_timing_driven -no_iobuf " \
|
|
433
451
|
+ f"-top {top} {incdirs} {defines} {v}",
|
|
@@ -631,10 +649,10 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
631
649
|
eda_path = eda_base.get_eda_exec('flist')
|
|
632
650
|
command_list = [
|
|
633
651
|
eda_path, 'flist',
|
|
634
|
-
'--tool'
|
|
652
|
+
'--tool=' + self.args['tool'],
|
|
635
653
|
self.args['top-path'],
|
|
636
654
|
'--force',
|
|
637
|
-
'--out'
|
|
655
|
+
'--out=' + flist_file,
|
|
638
656
|
#'--no-emit-incdir',
|
|
639
657
|
#'--no-single-quote-define', # Needed to run in Command.exec( ... shell=False)
|
|
640
658
|
'--no-quote-define',
|
|
@@ -644,11 +662,11 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
644
662
|
'--no-equal-define',
|
|
645
663
|
'--bracket-quote-path',
|
|
646
664
|
# on --prefix- items, use shlex.quote(str) so spaces work with subprocess shell=False:
|
|
647
|
-
'--prefix-incdir'
|
|
648
|
-
'--prefix-define'
|
|
649
|
-
'--prefix-sv'
|
|
650
|
-
'--prefix-v'
|
|
651
|
-
'--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 "),
|
|
652
670
|
]
|
|
653
671
|
for key,value in self.defines.items():
|
|
654
672
|
if value is None:
|
|
@@ -656,6 +674,7 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
|
|
|
656
674
|
else:
|
|
657
675
|
command_list += [ shlex.quote(f"+define+{key}={value}") ]
|
|
658
676
|
cwd = util.getcwd()
|
|
677
|
+
util.debug(f"CommandBuildVivado: {cwd=}")
|
|
659
678
|
|
|
660
679
|
|
|
661
680
|
# Write out a .sh command, but only for debug, it is not run.
|