opencos-eda 0.2.56__py3-none-any.whl → 0.3.0__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/_version.py +6 -3
- opencos/_waves_pkg.sv +34 -2
- opencos/commands/build.py +1 -0
- opencos/commands/export.py +1 -0
- opencos/commands/flist.py +1 -0
- opencos/commands/lec.py +5 -0
- opencos/commands/multi.py +4 -0
- opencos/commands/proj.py +1 -0
- opencos/commands/shell.py +4 -0
- opencos/commands/sim.py +47 -1
- opencos/commands/synth.py +4 -0
- opencos/deps/defaults.py +15 -7
- opencos/deps/deps_commands.py +84 -74
- opencos/deps_schema.py +3 -0
- opencos/eda.py +15 -2
- opencos/eda_base.py +61 -16
- opencos/eda_config.py +35 -1
- opencos/eda_config_defaults.yml +3 -1
- opencos/export_helper.py +5 -1
- opencos/tests/deps_files/command_order/DEPS.yml +11 -0
- opencos/tests/helpers.py +57 -19
- opencos/tests/test_deps_helpers.py +37 -25
- opencos/tests/test_eda.py +26 -60
- opencos/tools/cocotb.py +25 -0
- opencos/tools/modelsim_ase.py +65 -16
- opencos/tools/riviera.py +31 -6
- opencos/tools/slang_yosys.py +4 -1
- opencos/tools/verilator.py +28 -38
- opencos/tools/yosys.py +50 -20
- opencos/util.py +63 -12
- opencos/utils/vscode_helper.py +1 -1
- opencos/utils/vsim_helper.py +2 -3
- {opencos_eda-0.2.56.dist-info → opencos_eda-0.3.0.dist-info}/METADATA +2 -1
- {opencos_eda-0.2.56.dist-info → opencos_eda-0.3.0.dist-info}/RECORD +39 -39
- {opencos_eda-0.2.56.dist-info → opencos_eda-0.3.0.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.56.dist-info → opencos_eda-0.3.0.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.56.dist-info → opencos_eda-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.56.dist-info → opencos_eda-0.3.0.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.56.dist-info → opencos_eda-0.3.0.dist-info}/top_level.txt +0 -0
opencos/tools/cocotb.py
CHANGED
|
@@ -100,9 +100,34 @@ class CommandSimCocotb(CommandSim, ToolCocotb):
|
|
|
100
100
|
def set_tool_defines(self):
|
|
101
101
|
ToolCocotb.set_tool_defines(self)
|
|
102
102
|
|
|
103
|
+
def help( # pylint: disable=dangerous-default-value
|
|
104
|
+
self, tokens: list = [], no_targets: bool = False
|
|
105
|
+
) -> None:
|
|
106
|
+
'''Override for Command.help(...)'''
|
|
107
|
+
|
|
108
|
+
super().help(tokens=tokens, no_targets=no_targets)
|
|
109
|
+
self._warn_if_simulator_not_present()
|
|
110
|
+
|
|
111
|
+
def _warn_if_simulator_not_present(self) -> None:
|
|
112
|
+
'''Warn if --cocotb-simulator is not set, or if the exe is not in PATH'''
|
|
113
|
+
|
|
114
|
+
simulator = self.args['cocotb-simulator']
|
|
115
|
+
if not simulator:
|
|
116
|
+
util.warning('--cocotb-simulator is not set, a simulation cannot be run with'
|
|
117
|
+
'this arg value')
|
|
118
|
+
return
|
|
119
|
+
exe = shutil.which(simulator)
|
|
120
|
+
if not exe:
|
|
121
|
+
util.warning(f'--cocotb-simulator={simulator}, {simulator} is not present in PATH',
|
|
122
|
+
'a simulation cannot be run with this arg value')
|
|
123
|
+
|
|
124
|
+
|
|
103
125
|
def prepare_compile(self):
|
|
104
126
|
self.set_tool_defines()
|
|
105
127
|
|
|
128
|
+
# Check existence of cocotb-simulator:
|
|
129
|
+
self._warn_if_simulator_not_present()
|
|
130
|
+
|
|
106
131
|
# Fix iverilog -> icarus
|
|
107
132
|
if self.args['cocotb-simulator'] == 'iverilog':
|
|
108
133
|
self.args['cocotb-simulator'] = 'icarus'
|
opencos/tools/modelsim_ase.py
CHANGED
|
@@ -10,7 +10,7 @@ Note that this is for 32-bit Modelsim Student Edition. Consider using --tool=que
|
|
|
10
10
|
import os
|
|
11
11
|
|
|
12
12
|
from opencos import util
|
|
13
|
-
from opencos.commands import CommandSim
|
|
13
|
+
from opencos.commands import sim, CommandSim
|
|
14
14
|
from opencos.tools.questa import ToolQuesta
|
|
15
15
|
from opencos.utils.str_helpers import sanitize_defines_for_sh
|
|
16
16
|
|
|
@@ -32,6 +32,14 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
32
32
|
self.args.update({
|
|
33
33
|
'tool': self._TOOL, # override
|
|
34
34
|
'gui': False,
|
|
35
|
+
'vopt': self.use_vopt,
|
|
36
|
+
})
|
|
37
|
+
self.args_help.update({
|
|
38
|
+
'vopt': (
|
|
39
|
+
'Boolean to enable/disable use of vopt step prior to vsim step'
|
|
40
|
+
' Note that vopt args can be controlled with --elab-args=<value1>'
|
|
41
|
+
' --elab-args=<value2> ...'
|
|
42
|
+
)
|
|
35
43
|
})
|
|
36
44
|
|
|
37
45
|
def set_tool_defines(self):
|
|
@@ -158,7 +166,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
158
166
|
'compile-waivers',
|
|
159
167
|
[ #defaults:
|
|
160
168
|
'2275', # 2275 - Existing package 'foo_pkg' will be overwritten.
|
|
161
|
-
]):
|
|
169
|
+
]) + self.args['compile-waivers']:
|
|
162
170
|
vlog_dot_f_lines += ['-suppress', str(waiver)]
|
|
163
171
|
|
|
164
172
|
if self.args['gui'] or self.args['waves']:
|
|
@@ -201,6 +209,44 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
201
209
|
with open(vlog_dot_f_fpath, 'w', encoding='utf-8') as f:
|
|
202
210
|
f.writelines(line + "\n" for line in vlog_dot_f_lines)
|
|
203
211
|
|
|
212
|
+
def vopt_handle_parameters(self) -> (str, list):
|
|
213
|
+
'''Returns str for vopt or voptargs, and list of vopt tcl
|
|
214
|
+
|
|
215
|
+
Note this is used for self.use_vopt = True or False.
|
|
216
|
+
'''
|
|
217
|
+
|
|
218
|
+
voptargs_str = ''
|
|
219
|
+
vopt_do_lines = []
|
|
220
|
+
|
|
221
|
+
# Note that if self.use_vopt=True, we have to do some workarounds for how
|
|
222
|
+
# some questa-like tools behave for: tcl/.do + vopt arg processing
|
|
223
|
+
# This affects string based parameters that have spaces (vopt treats spaces unique args,
|
|
224
|
+
# vsim does not). Since we'd like to keep the vopt/vsim split into separate steps, we can
|
|
225
|
+
# work around this by setting tcl varaibles for each parameter.
|
|
226
|
+
if self.parameters:
|
|
227
|
+
if not self.use_vopt:
|
|
228
|
+
voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
|
|
229
|
+
else:
|
|
230
|
+
for k,v in self.parameters.items():
|
|
231
|
+
s = sim.parameters_dict_get_command_list(params={k: v}, arg_prefix='')[0]
|
|
232
|
+
# At this point, s should be a str in form {k}={v}
|
|
233
|
+
if not s or '=' not in s:
|
|
234
|
+
continue
|
|
235
|
+
if ' ' in s:
|
|
236
|
+
# Instead of:
|
|
237
|
+
# vopt -GMyParam="hi bye"
|
|
238
|
+
# we'll do:
|
|
239
|
+
# set PARAMETERS(MyParam) "hi bye"
|
|
240
|
+
# vopt -GMyParam=$PARAMETERS(MyParam)
|
|
241
|
+
s = s.replace(f'{k}=', f'set PARAMETERS({k}) ')
|
|
242
|
+
vopt_do_lines.append(s)
|
|
243
|
+
voptargs_str += f' -G{k}=$PARAMETERS({k}) '
|
|
244
|
+
else:
|
|
245
|
+
voptargs_str += f' -G{s} '
|
|
246
|
+
|
|
247
|
+
return voptargs_str, vopt_do_lines
|
|
248
|
+
|
|
249
|
+
|
|
204
250
|
def write_vsim_dot_do( # pylint: disable=too-many-locals
|
|
205
251
|
self, dot_do_to_write: list
|
|
206
252
|
) -> None:
|
|
@@ -214,21 +260,25 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
214
260
|
|
|
215
261
|
sim_plusargs_str = self._get_sim_plusargs_str()
|
|
216
262
|
vsim_suppress_list_str = self._get_vsim_suppress_list_str()
|
|
263
|
+
vsim_ext_args = ' '.join(self.args.get('sim-args', []))
|
|
217
264
|
|
|
218
|
-
voptargs_str =
|
|
265
|
+
voptargs_str = self.tool_config.get('elab-args', '')
|
|
266
|
+
voptargs_str += ' '.join(self.args.get('elab-args', []))
|
|
219
267
|
if self.args['gui'] or self.args['waves']:
|
|
220
|
-
voptargs_str
|
|
268
|
+
voptargs_str += ' ' + self.tool_config.get('simulate-waves-args', '+acc')
|
|
221
269
|
util.artifacts.add_extension(
|
|
222
270
|
search_paths=self.args['work-dir'], file_extension='wlf',
|
|
223
271
|
typ='waveform', description='Modelsim/Questa Waveform WLF (Wave Log Format) file'
|
|
224
272
|
)
|
|
225
273
|
|
|
226
|
-
#
|
|
227
|
-
|
|
228
|
-
|
|
274
|
+
# TODO(drew): support self.args['sim_libary'] (1 lists)
|
|
275
|
+
vlog_do_lines = []
|
|
276
|
+
vsim_do_lines = []
|
|
277
|
+
|
|
278
|
+
# parameters, use helper method to get voptargs_str and vopt_do_lines
|
|
279
|
+
more_voptargs_str, vopt_do_lines = self.vopt_handle_parameters()
|
|
280
|
+
voptargs_str += more_voptargs_str
|
|
229
281
|
|
|
230
|
-
# TODO(drew): support self.args['sim_libary', 'elab-args', sim-args'] (3 lists)
|
|
231
|
-
# to add to vsim_one_liner.
|
|
232
282
|
|
|
233
283
|
vopt_one_liner = ""
|
|
234
284
|
if self.use_vopt:
|
|
@@ -241,17 +291,17 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
241
291
|
|
|
242
292
|
vsim_one_liner = "vsim -onfinish stop" \
|
|
243
293
|
+ f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
|
|
244
|
-
+ f" opt__{self.args['top']}"
|
|
294
|
+
+ f" {vsim_ext_args} opt__{self.args['top']}"
|
|
245
295
|
else:
|
|
246
296
|
# vopt doesn't exist, use single vsim call after vlog call:
|
|
247
297
|
vsim_one_liner = "vsim -onfinish stop" \
|
|
248
298
|
+ f" -sv_seed {self.args['seed']} {sim_plusargs_str} {vsim_suppress_list_str}" \
|
|
249
|
-
+ f" {voptargs_str} work.{self.args['top']}"
|
|
299
|
+
+ f" {voptargs_str} {vsim_ext_args} work.{self.args['top']}"
|
|
250
300
|
|
|
251
301
|
|
|
252
302
|
vsim_one_liner = vsim_one_liner.replace('\n', ' ')
|
|
253
303
|
|
|
254
|
-
vlog_do_lines
|
|
304
|
+
vlog_do_lines += [
|
|
255
305
|
"if {[file exists work]} { vdel -all work; }",
|
|
256
306
|
"vlib work;",
|
|
257
307
|
"quietly set qc 30;",
|
|
@@ -263,9 +313,8 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
263
313
|
"}",
|
|
264
314
|
]
|
|
265
315
|
|
|
266
|
-
vopt_do_lines = []
|
|
267
316
|
if self.use_vopt:
|
|
268
|
-
vopt_do_lines
|
|
317
|
+
vopt_do_lines += [
|
|
269
318
|
"if {[catch { " + vopt_one_liner + " } result] } {",
|
|
270
319
|
" echo \"Caught $result\";",
|
|
271
320
|
" if {[batch_mode]} {",
|
|
@@ -274,7 +323,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
274
323
|
"}",
|
|
275
324
|
]
|
|
276
325
|
|
|
277
|
-
vsim_do_lines
|
|
326
|
+
vsim_do_lines += [
|
|
278
327
|
"if {[catch { " + vsim_one_liner + " } result] } {",
|
|
279
328
|
" echo \"Caught $result\";",
|
|
280
329
|
" if {[batch_mode]} {",
|
|
@@ -352,7 +401,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
352
401
|
#defaults:
|
|
353
402
|
'3009', # 3009: [TSCALE] - Module 'foo' does not have a timeunit/timeprecision
|
|
354
403
|
# specification in effect, but other modules do.
|
|
355
|
-
]):
|
|
404
|
+
]) + self.args['sim-waivers']:
|
|
356
405
|
vsim_suppress_list += ['-suppress', str(waiver)]
|
|
357
406
|
|
|
358
407
|
return ' '.join(vsim_suppress_list)
|
opencos/tools/riviera.py
CHANGED
|
@@ -59,6 +59,17 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
59
59
|
self.args.update({
|
|
60
60
|
'tool': self._TOOL, # override
|
|
61
61
|
'gui': False,
|
|
62
|
+
'waves-fst': True,
|
|
63
|
+
'waves-vcd': False,
|
|
64
|
+
})
|
|
65
|
+
self.args_help.update({
|
|
66
|
+
'waves-fst': (
|
|
67
|
+
'(Default True) If using --waves, apply simulation runtime arg +trace.'
|
|
68
|
+
' Note that if you do not have SV code using $dumpfile, eda will add'
|
|
69
|
+
' _waves_pkg.sv to handle this for you with +trace runtime plusarg.'
|
|
70
|
+
),
|
|
71
|
+
'waves-vcd': 'If using --waves, apply simulation runtime arg +trace=vcd',
|
|
72
|
+
'waves': 'Save a .asdb offline wavefile, can be used with --waves-fst or --waves-vcd',
|
|
62
73
|
})
|
|
63
74
|
|
|
64
75
|
def set_tool_defines(self):
|
|
@@ -76,6 +87,9 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
76
87
|
|
|
77
88
|
def compile(self):
|
|
78
89
|
'''Override for CommandSimModelsimAse.compile() so we can set our own must_strings'''
|
|
90
|
+
|
|
91
|
+
self.add_waves_pkg_file()
|
|
92
|
+
|
|
79
93
|
if self.args['stop-before-compile']:
|
|
80
94
|
# don't run anything, save everyting we've already run in _prep_compile()
|
|
81
95
|
return
|
|
@@ -126,7 +140,8 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
126
140
|
'-sv -input_ports net').split()
|
|
127
141
|
|
|
128
142
|
# Add waivers from config.tool.riviera, convert to warning:
|
|
129
|
-
for waiver in self.tool_config.get('compile-waivers', [])
|
|
143
|
+
for waiver in self.tool_config.get('compile-waivers', []) + \
|
|
144
|
+
self.args['compile-waivers']:
|
|
130
145
|
vlog_dot_f_lines += [f'-err {waiver} W1']
|
|
131
146
|
|
|
132
147
|
vlog_dot_f_fname = filename
|
|
@@ -167,6 +182,7 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
167
182
|
f.writelines(line + "\n" for line in vlog_dot_f_lines)
|
|
168
183
|
|
|
169
184
|
|
|
185
|
+
|
|
170
186
|
def write_vsim_dot_do(self, dot_do_to_write: list) -> None:
|
|
171
187
|
'''Writes files(s) based on dot_do_to_write(list of str)
|
|
172
188
|
|
|
@@ -177,9 +193,18 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
177
193
|
vsim_vlogonly_dot_do_fpath = os.path.join(self.args['work-dir'], 'vsim_vlogonly.do')
|
|
178
194
|
|
|
179
195
|
sim_plusargs_str = self._get_sim_plusargs_str()
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if self.args['
|
|
196
|
+
vsim_ext_args = ' '.join(self.args.get('sim-args', []))
|
|
197
|
+
|
|
198
|
+
if self.args['waves'] and '+trace' not in sim_plusargs_str:
|
|
199
|
+
if self.args.get('waves-vcd', False):
|
|
200
|
+
sim_plusargs_str += ' +trace=vcd'
|
|
201
|
+
elif self.args.get('waves-fst', False):
|
|
202
|
+
sim_plusargs_str += ' +trace'
|
|
203
|
+
|
|
204
|
+
voptargs_str = self.tool_config.get('elab-args', '')
|
|
205
|
+
voptargs_str += ' '.join(self.args.get('elab-args', []))
|
|
206
|
+
if self.args['gui'] or self.args['waves'] or self.args['coverage']: # \
|
|
207
|
+
#or self.args['waves-asdb']:
|
|
183
208
|
voptargs_str += self.tool_config.get('simulate-waves-args',
|
|
184
209
|
'+accb +accr +access +r+w')
|
|
185
210
|
if self.args['coverage']:
|
|
@@ -195,7 +220,7 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
195
220
|
vsim_one_liner = (
|
|
196
221
|
"vsim"
|
|
197
222
|
f" -sv_seed {self.args['seed']} {sim_plusargs_str}"
|
|
198
|
-
f" {voptargs_str} work.{self.args['top']}"
|
|
223
|
+
f" {voptargs_str} {vsim_ext_args} work.{self.args['top']}"
|
|
199
224
|
)
|
|
200
225
|
|
|
201
226
|
vsim_one_liner = vsim_one_liner.replace('\n', ' ') # needs to be a one-liner
|
|
@@ -294,7 +319,7 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
294
319
|
for waiver in self.tool_config.get(
|
|
295
320
|
'simulate-waivers', [
|
|
296
321
|
#defaults: none
|
|
297
|
-
]):
|
|
322
|
+
]) + self.args['sim-waivers']:
|
|
298
323
|
vsim_suppress_list += ['-filter', str(waiver)]
|
|
299
324
|
|
|
300
325
|
return ' '.join(vsim_suppress_list)
|
opencos/tools/slang_yosys.py
CHANGED
|
@@ -118,7 +118,10 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
118
118
|
params=self.parameters, arg_prefix='-G '
|
|
119
119
|
)
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
# In case --top was not set:
|
|
122
|
+
if not any(x.startswith('--top') for x in read_slang_cmd):
|
|
123
|
+
read_slang_cmd.append(f'--top {self.args["top"]}')
|
|
124
|
+
|
|
122
125
|
return ' '.join(read_slang_cmd)
|
|
123
126
|
|
|
124
127
|
|
opencos/tools/verilator.py
CHANGED
|
@@ -76,6 +76,8 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
76
76
|
'gui': False,
|
|
77
77
|
'tcl-file': None,
|
|
78
78
|
'dump-vcd': False,
|
|
79
|
+
'waves-fst': True,
|
|
80
|
+
'waves-vcd': False,
|
|
79
81
|
'lint-only': False,
|
|
80
82
|
'cc-mode': False,
|
|
81
83
|
'verilator-coverage-args': [],
|
|
@@ -84,12 +86,22 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
84
86
|
})
|
|
85
87
|
|
|
86
88
|
self.args_help.update({
|
|
87
|
-
'waves':
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
'waves': (
|
|
90
|
+
'Include waveforms, if possible for Verilator by applying'
|
|
91
|
+
' simulation runtime arg +trace. User will need SV code to interpret the'
|
|
92
|
+
' plusarg and apply $dumpfile("dump.fst").'
|
|
93
|
+
),
|
|
94
|
+
'waves-fst': (
|
|
95
|
+
'(Default True) If using --waves, apply simulation runtime arg +trace.'
|
|
96
|
+
' Note that if you do not have SV code using $dumpfile, eda will add'
|
|
97
|
+
' _waves_pkg.sv to handle this for you with +trace runtime plusarg.'
|
|
98
|
+
),
|
|
99
|
+
'waves-vcd': (
|
|
100
|
+
'If using --waves, apply simulation runtime arg +trace=vcd. User'
|
|
101
|
+
' will need SV code to interpret the plusarg and apply'
|
|
102
|
+
' $dumpfile("dump.vcd").'
|
|
103
|
+
),
|
|
104
|
+
'dump-vcd': 'Same as --waves-vcd',
|
|
93
105
|
'lint-only': 'Run verilator with --lint-only, instead of --binary',
|
|
94
106
|
'gui': 'Not supported for Verilator',
|
|
95
107
|
'cc-mode': 'Run verilator with --cc, requires a sim_main.cpp or similar sources',
|
|
@@ -124,7 +136,7 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
124
136
|
if self.files_cpp:
|
|
125
137
|
self.args['cc-mode'] = True
|
|
126
138
|
|
|
127
|
-
self.
|
|
139
|
+
self.add_waves_pkg_file()
|
|
128
140
|
|
|
129
141
|
# Each of these should be a list of util.ShellCommandList()
|
|
130
142
|
self.verilate_command_lists = self.get_compile_command_lists()
|
|
@@ -300,9 +312,10 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
300
312
|
# Built-in support for eda args --waves and/or --dump-vcd to become runtime
|
|
301
313
|
# plusargs +trace or +trace=vcd, if +trace or +trace= was not already in our
|
|
302
314
|
# plusargs.
|
|
303
|
-
if self.args.get('dump-vcd', False)
|
|
315
|
+
if self.args.get('dump-vcd', False) or \
|
|
316
|
+
self.args.get('waves-vcd', False):
|
|
304
317
|
sim_plusargs.append('+trace=vcd')
|
|
305
|
-
|
|
318
|
+
elif self.args.get('waves-fst', False):
|
|
306
319
|
sim_plusargs.append('+trace')
|
|
307
320
|
|
|
308
321
|
verilated_exec_command_list += config_sim_args + sim_plusargs + self.args['sim-args']
|
|
@@ -351,40 +364,17 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
351
364
|
|
|
352
365
|
return []
|
|
353
366
|
|
|
354
|
-
def
|
|
367
|
+
def add_waves_pkg_file(self) -> None:
|
|
355
368
|
'''If --waves present, and the user is missing any $dumpfile(), then adds a pre-written
|
|
356
369
|
SystemVerilog package to their source code.
|
|
357
370
|
'''
|
|
358
|
-
if not self.args['waves']:
|
|
359
|
-
return
|
|
360
371
|
if self.args['cc-mode']:
|
|
361
|
-
# We won't do this if the user
|
|
372
|
+
# We won't do this if the user brought a .cpp file and verilator not
|
|
362
373
|
# called with --binary.
|
|
363
374
|
return
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
break
|
|
368
|
-
with open(fname, encoding='utf-8') as f:
|
|
369
|
-
for line in f.readlines():
|
|
370
|
-
if '$dumpfile' in line:
|
|
371
|
-
found_dumpfile = True
|
|
372
|
-
break
|
|
373
|
-
if not found_dumpfile:
|
|
374
|
-
thispath = os.path.dirname(__file__)
|
|
375
|
-
file_to_add = os.path.join(thispath, '..', '_waves_pkg.sv')
|
|
376
|
-
util.info(f'--waves arg present, no $dumpfile found, adding SV file: {file_to_add}')
|
|
377
|
-
self.add_file(file_to_add)
|
|
378
|
-
|
|
379
|
-
# register .vcd or .fst artifacts:
|
|
380
|
-
util.artifacts.add_extension(
|
|
381
|
-
search_paths=self.args['work-dir'], file_extension='fst',
|
|
382
|
-
typ='waveform', description='Simulation Waveform FST (Fast Signal Trace) file'
|
|
383
|
-
)
|
|
384
|
-
util.artifacts.add_extension(
|
|
385
|
-
search_paths=self.args['work-dir'], file_extension='vcd',
|
|
386
|
-
typ='waveform', description='Simulation Waveform VCD (Value Change Dump) file'
|
|
387
|
-
)
|
|
375
|
+
|
|
376
|
+
super().add_waves_pkg_file() # call from CommandSim
|
|
377
|
+
|
|
388
378
|
|
|
389
379
|
|
|
390
380
|
def _get_start_verilator_command_list(self, lint_only: bool = False) -> list:
|
|
@@ -415,7 +405,7 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
415
405
|
[ #defaults:
|
|
416
406
|
'CASEINCOMPLETE',
|
|
417
407
|
'TIMESCALEMOD', # If one file has `timescale, then they all must
|
|
418
|
-
]):
|
|
408
|
+
]) + self.args['compile-waivers']:
|
|
419
409
|
ret.append(f'-Wno-{waiver}')
|
|
420
410
|
return ret
|
|
421
411
|
|
opencos/tools/yosys.py
CHANGED
|
@@ -536,7 +536,6 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
536
536
|
|
|
537
537
|
self.synth_designs_tops = [None, None]
|
|
538
538
|
self.synth_designs_fpaths = [None, None]
|
|
539
|
-
self.synth_design_top_module_names = [None, None]
|
|
540
539
|
|
|
541
540
|
def get_synth_result_fpath(self, target: str) -> str:
|
|
542
541
|
'''Overridden from CommandLec'''
|
|
@@ -547,7 +546,7 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
547
546
|
def get_synth_command_list(self, design_num: int) -> list:
|
|
548
547
|
'''Returns one of the synthesis command lists, for design_num=0 or 1'''
|
|
549
548
|
|
|
550
|
-
if not design_num in
|
|
549
|
+
if not design_num in (0, 1):
|
|
551
550
|
self.error(f'{design_num=} we only support LEC on designs 0 and 1')
|
|
552
551
|
|
|
553
552
|
synth_cmd_list = [
|
|
@@ -561,31 +560,43 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
561
560
|
synth_cmd_list += [
|
|
562
561
|
'--work-dir=' + self.synth_work_dirs[design_num],
|
|
563
562
|
self.args['designs'][design_num],
|
|
564
|
-
f'--rename-module=Design{design_num + 1}'
|
|
563
|
+
f'--rename-module=Design{design_num + 1}',
|
|
565
564
|
]
|
|
566
565
|
|
|
567
|
-
self.
|
|
566
|
+
if self.args['flatten-all']:
|
|
567
|
+
# We have to do this or may get conflicts on black-boxed modules, but can
|
|
568
|
+
# be avoided with --no-flatten-all.
|
|
569
|
+
synth_cmd_list.append(
|
|
570
|
+
'--flatten-all'
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
self.synth_designs_tops[design_num] = f'Design{design_num + 1}'
|
|
568
574
|
|
|
569
575
|
return synth_cmd_list
|
|
570
576
|
|
|
571
577
|
|
|
572
|
-
def get_synth_top_from_output_config(self, design_num: int) -> str:
|
|
573
|
-
'''Returns the top name given the design number
|
|
578
|
+
def get_synth_top_from_output_config(self, design_num: int) -> (str, str):
|
|
579
|
+
'''Returns the (orignal top name, module name) tuple given the design number
|
|
580
|
+
|
|
581
|
+
that we synthesized'''
|
|
574
582
|
|
|
575
583
|
work_dir = self.synth_work_dirs[design_num]
|
|
576
584
|
output_cfg_fpath = os.path.join(work_dir, eda_config.EDA_OUTPUT_CONFIG_FNAME)
|
|
577
585
|
data = yaml_safe_load(output_cfg_fpath)
|
|
578
586
|
top = data.get('args', {}).get('top', '')
|
|
579
|
-
|
|
587
|
+
rename_module = data.get('args', {}).get('rename-module', '')
|
|
588
|
+
if not top and not rename_module:
|
|
580
589
|
self.error(f'"top" not found in synth run from {work_dir=} in',
|
|
581
590
|
f'config {output_cfg_fpath}')
|
|
582
|
-
|
|
591
|
+
if not rename_module:
|
|
592
|
+
return top, top
|
|
593
|
+
return top, rename_module
|
|
583
594
|
|
|
584
595
|
|
|
585
596
|
def get_synth_results_fpath(self, design_num: int, top: str) -> str:
|
|
586
|
-
'''Returns the synthesized .v file fpath'''
|
|
597
|
+
'''Returns the synthesized .v file fpath, using orignal top (not renamed)'''
|
|
587
598
|
if not top:
|
|
588
|
-
top = self.get_synth_top_from_output_config(design_num=design_num)
|
|
599
|
+
top, _ = self.get_synth_top_from_output_config(design_num=design_num)
|
|
589
600
|
|
|
590
601
|
work_dir = self.synth_work_dirs[design_num]
|
|
591
602
|
fpath = os.path.join(work_dir, 'yosys', f'{top}.v')
|
|
@@ -594,7 +605,7 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
594
605
|
return fpath
|
|
595
606
|
|
|
596
607
|
|
|
597
|
-
def do_it(self) -> None:
|
|
608
|
+
def do_it(self) -> None: # pylint: disable=too-many-locals,too-many-statements,too-many-branches
|
|
598
609
|
self.set_tool_defines()
|
|
599
610
|
self.write_eda_config_and_args()
|
|
600
611
|
|
|
@@ -622,6 +633,9 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
622
633
|
self.exec(work_dir=self.args['work-dir'], command_list=x,
|
|
623
634
|
tee_fpath=x.tee_fpath)
|
|
624
635
|
|
|
636
|
+
util.info(f'LEC ran via --yosys-scriptfile: {self.args["yosys-scriptfile"]}')
|
|
637
|
+
return
|
|
638
|
+
|
|
625
639
|
|
|
626
640
|
if self.args['synth']:
|
|
627
641
|
synth1_cmd_list = self.get_synth_command_list(design_num=0)
|
|
@@ -636,23 +650,23 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
636
650
|
self.exec(pwd, synth2_cmd_list, background=True)
|
|
637
651
|
util.info(f'Finished with 2nd LEC synthesis {self.args["designs"][1]}')
|
|
638
652
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
]
|
|
653
|
+
|
|
654
|
+
top0, module0 = self.get_synth_top_from_output_config(design_num=0)
|
|
655
|
+
top1, module1 = self.get_synth_top_from_output_config(design_num=1)
|
|
656
|
+
self.synth_designs_tops = [module0, module1]
|
|
643
657
|
util.info(f'Design tops: {self.synth_designs_tops}')
|
|
644
658
|
|
|
645
659
|
# read the output config
|
|
646
660
|
self.synth_designs_fpaths = [
|
|
647
661
|
os.path.abspath(
|
|
648
|
-
self.get_synth_results_fpath(design_num=0, top=
|
|
662
|
+
self.get_synth_results_fpath(design_num=0, top=top0)),
|
|
649
663
|
os.path.abspath(
|
|
650
|
-
self.get_synth_results_fpath(design_num=1, top=
|
|
664
|
+
self.get_synth_results_fpath(design_num=1, top=top1))
|
|
651
665
|
]
|
|
652
666
|
util.info(f'Design tops: {self.synth_designs_fpaths}')
|
|
653
667
|
|
|
654
668
|
else:
|
|
655
|
-
# don't run synthesis, need the two top level .v files in
|
|
669
|
+
# don't run synthesis, need the two top level .v|.sv files in
|
|
656
670
|
# self.synth_designs_fpaths, and need the two top module names in
|
|
657
671
|
# self.synth_designs_tops
|
|
658
672
|
self.synth_designs_fpaths = [
|
|
@@ -660,11 +674,19 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
660
674
|
os.path.abspath(self.args['designs'][1])
|
|
661
675
|
]
|
|
662
676
|
|
|
677
|
+
for i in (0, 1):
|
|
678
|
+
if not os.path.isfile(self.args['designs'][i]):
|
|
679
|
+
self.error(
|
|
680
|
+
'Using synth=False (--no-synth) --designs=<value> must be a single',
|
|
681
|
+
f'filename, however {self.args["designs"][i]} does not exist'
|
|
682
|
+
)
|
|
683
|
+
|
|
663
684
|
path, fname = os.path.split(self.synth_designs_fpaths[0])
|
|
664
685
|
module_guess, _ = os.path.splitext(fname)
|
|
665
686
|
top1 = util.get_inferred_top_module_name(
|
|
666
687
|
module_guess=module_guess, module_fpath=self.synth_designs_fpaths[0]
|
|
667
688
|
)
|
|
689
|
+
util.debug(f'design1 {module_guess=} {fname=} {path=}')
|
|
668
690
|
util.info(f'design1 top module name = {top1} (from {path} / {fname})')
|
|
669
691
|
|
|
670
692
|
path, fname = os.path.split(self.synth_designs_fpaths[1])
|
|
@@ -672,6 +694,7 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
672
694
|
top2 = util.get_inferred_top_module_name(
|
|
673
695
|
module_guess=module_guess, module_fpath=self.synth_designs_fpaths[1]
|
|
674
696
|
)
|
|
697
|
+
util.debug(f'design2 {module_guess=} {fname=} {path=}')
|
|
675
698
|
util.info(f'design2 top module name = {top2} (from {path} / {fname})')
|
|
676
699
|
|
|
677
700
|
self.synth_designs_tops = [top1, top2]
|
|
@@ -691,13 +714,20 @@ class CommandLecYosys(CommandLec, ToolYosys):
|
|
|
691
714
|
]
|
|
692
715
|
else:
|
|
693
716
|
self.error(f' --pre-read-verilog file {x} does not exist')
|
|
717
|
+
|
|
718
|
+
nooverwrite = ''
|
|
719
|
+
if self.args['synth'] and not self.args['flatten-all']:
|
|
720
|
+
# If we don't flatten-all from synthesis, and we had to run synthesis,
|
|
721
|
+
# then read the 2nd file with -overwrite
|
|
722
|
+
nooverwrite = '-nooverwrite'
|
|
723
|
+
|
|
694
724
|
lec_cmd_f_list += [
|
|
695
725
|
'# Design1 (module):',
|
|
696
726
|
f'read_verilog -sv -icells {self.synth_designs_fpaths[0]}',
|
|
697
727
|
'# Design2 (module):',
|
|
698
|
-
f'read_verilog -sv -icells {self.synth_designs_fpaths[1]}',
|
|
728
|
+
f'read_verilog -sv -icells {self.synth_designs_fpaths[1]} {nooverwrite}',
|
|
699
729
|
'clk2fflogic;',
|
|
700
|
-
f'miter -equiv -flatten {" ".join(self.
|
|
730
|
+
f'miter -equiv -flatten {" ".join(self.synth_designs_tops)} miter',
|
|
701
731
|
('sat -seq 50 -verify -prove trigger 0 -show-all -show-inputs -show-outputs'
|
|
702
732
|
' -set-init-zero miter'),
|
|
703
733
|
]
|