opencos-eda 0.2.55__py3-none-any.whl → 0.2.57__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/flist.py +10 -0
- opencos/commands/lec.py +4 -0
- opencos/commands/multi.py +4 -0
- opencos/commands/sim.py +31 -0
- opencos/deps/defaults.py +2 -0
- opencos/deps/deps_processor.py +39 -1
- opencos/deps_schema.py +22 -0
- opencos/eda.py +13 -1
- opencos/eda_base.py +108 -10
- opencos/eda_config.py +37 -2
- opencos/eda_config_defaults.yml +1 -0
- opencos/export_helper.py +20 -6
- opencos/hw/oc_cli.py +1 -1
- opencos/names.py +4 -1
- opencos/tests/helpers.py +9 -0
- opencos/tests/test_eda_synth.py +12 -0
- opencos/tools/cocotb.py +25 -0
- opencos/tools/invio_helpers.py +25 -4
- opencos/tools/iverilog.py +5 -0
- opencos/tools/modelsim_ase.py +52 -6
- opencos/tools/quartus.py +32 -6
- opencos/tools/riviera.py +17 -3
- opencos/tools/slang.py +5 -0
- opencos/tools/slang_yosys.py +13 -1
- opencos/tools/surelog.py +5 -0
- opencos/tools/verilator.py +5 -0
- opencos/tools/vivado.py +15 -2
- opencos/tools/yosys.py +50 -20
- opencos/utils/vsim_helper.py +1 -2
- {opencos_eda-0.2.55.dist-info → opencos_eda-0.2.57.dist-info}/METADATA +1 -1
- {opencos_eda-0.2.55.dist-info → opencos_eda-0.2.57.dist-info}/RECORD +36 -36
- {opencos_eda-0.2.55.dist-info → opencos_eda-0.2.57.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.55.dist-info → opencos_eda-0.2.57.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.55.dist-info → opencos_eda-0.2.57.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.55.dist-info → opencos_eda-0.2.57.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.55.dist-info → opencos_eda-0.2.57.dist-info}/top_level.txt +0 -0
opencos/tests/helpers.py
CHANGED
|
@@ -39,6 +39,15 @@ def can_run_eda_command(*commands, config: dict) -> bool:
|
|
|
39
39
|
if handler and getattr(handler, 'CHECK_REQUIRES', []):
|
|
40
40
|
if not all(issubclass(handler, x) for x in getattr(handler, 'CHECK_REQUIRES', [])):
|
|
41
41
|
return False
|
|
42
|
+
|
|
43
|
+
# We cannot run tools that have disable-auto set:
|
|
44
|
+
tool = getattr(handler, '_TOOL', '')
|
|
45
|
+
if handler and tool:
|
|
46
|
+
entry = config['auto_tools_order'][0].get(tool, {})
|
|
47
|
+
if entry and entry.get('disable-auto', False):
|
|
48
|
+
# This tool cannot automatically run our command.
|
|
49
|
+
return False
|
|
50
|
+
|
|
42
51
|
runnable.append(True)
|
|
43
52
|
return runnable and all(runnable)
|
|
44
53
|
|
opencos/tests/test_eda_synth.py
CHANGED
|
@@ -8,6 +8,7 @@ import pytest
|
|
|
8
8
|
from opencos import eda, eda_tool_helper
|
|
9
9
|
from opencos.tests import helpers
|
|
10
10
|
from opencos.tests.helpers import Helpers
|
|
11
|
+
from opencos.utils.markup_helpers import yaml_safe_load
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
THISPATH = os.path.dirname(__file__)
|
|
@@ -108,6 +109,17 @@ class TestsSlangYosys(Helpers):
|
|
|
108
109
|
rc = self.log_it(cmd_str, use_eda_wrap=False)
|
|
109
110
|
assert rc == 0
|
|
110
111
|
|
|
112
|
+
# Since vanilla yosys won't use the SDC file, let's at least confirm
|
|
113
|
+
# that EDA used it and tracked it:
|
|
114
|
+
eda_config_yml_path = os.path.join(
|
|
115
|
+
os.getcwd(), 'eda.work', 'oclib_fifo_with_sdc.synth', 'eda_output_config.yml'
|
|
116
|
+
)
|
|
117
|
+
data = yaml_safe_load(eda_config_yml_path)
|
|
118
|
+
assert 'files_sdc' in data
|
|
119
|
+
assert data['files_sdc']
|
|
120
|
+
assert data['files_sdc'][0].endswith('oclib_fifo_yosys.sdc')
|
|
121
|
+
|
|
122
|
+
|
|
111
123
|
@pytest.mark.skipif('vivado' not in tools_loaded, reason="requires vivado")
|
|
112
124
|
@pytest.mark.skipif(not vivado_has_xpms(), reason="requires install to have XPMs")
|
|
113
125
|
class TestsVivado(Helpers):
|
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/invio_helpers.py
CHANGED
|
@@ -61,6 +61,12 @@ def write_py_file(
|
|
|
61
61
|
'from invio import init, define_macro, add_include_directory, \\',
|
|
62
62
|
' add_verilog_file, add_sv_file, elaborate, elaborate_pct, analyze, \\',
|
|
63
63
|
' print_instance_hierarchy, write_design, report_analyzed_files',
|
|
64
|
+
]
|
|
65
|
+
if command_design_obj.parameters:
|
|
66
|
+
lines += [
|
|
67
|
+
'from invio import get_parameters, report_parameters, replace_expression_of_parameter'
|
|
68
|
+
]
|
|
69
|
+
lines += [
|
|
64
70
|
'import os, shutil',
|
|
65
71
|
'',
|
|
66
72
|
'for p in ["invio"]:',
|
|
@@ -138,18 +144,34 @@ def write_py_file(
|
|
|
138
144
|
tee_fpath = 'invio.log')]
|
|
139
145
|
})
|
|
140
146
|
|
|
147
|
+
lines += [
|
|
148
|
+
'assert analyze()',
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
if command_design_obj.parameters:
|
|
152
|
+
lines += [
|
|
153
|
+
'',
|
|
154
|
+
f'new_parameters = {command_design_obj.parameters}',
|
|
155
|
+
'for x in get_parameters():',
|
|
156
|
+
' name_parts = x.full_name.split("::")',
|
|
157
|
+
' mod, pname = name_parts[-2], name_parts[-1]',
|
|
158
|
+
f' if pname in new_parameters and mod == "{top}":',
|
|
159
|
+
' new_value = str(new_parameters[pname]) # invio needs str type for all',
|
|
160
|
+
' print(f"PARAMETER UPDATE: {mod}.{pname} ---> {new_value}")',
|
|
161
|
+
' replace_expression_of_parameter(x, new_value)',
|
|
162
|
+
'report_parameters()',
|
|
163
|
+
'',
|
|
164
|
+
]
|
|
165
|
+
|
|
141
166
|
if sim_lint:
|
|
142
167
|
# lint (skip elaborate steps -- from eda.CommandLintInvio)
|
|
143
168
|
lines += [
|
|
144
|
-
'assert analyze()',
|
|
145
|
-
'',
|
|
146
169
|
'report_analyzed_files()',
|
|
147
170
|
'print_instance_hierarchy()',
|
|
148
171
|
]
|
|
149
172
|
elif sim_elab:
|
|
150
173
|
# elab (non-synthesis), runs the following (from eda.CommandElabInvio)
|
|
151
174
|
lines += [
|
|
152
|
-
'assert analyze()',
|
|
153
175
|
f"assert elaborate('{top}', pct_elaboration=True, forceBlackbox={blackbox_list})",
|
|
154
176
|
'assert elaborate_pct()',
|
|
155
177
|
'',
|
|
@@ -159,7 +181,6 @@ def write_py_file(
|
|
|
159
181
|
else:
|
|
160
182
|
# synthesis-style elab (from eda.CommandElabInvioYosys)
|
|
161
183
|
lines += [
|
|
162
|
-
'assert analyze()',
|
|
163
184
|
f"assert elaborate('{top}', rtl_elaboration=True, forceBlackbox={blackbox_list})",
|
|
164
185
|
'',
|
|
165
186
|
'report_analyzed_files()',
|
opencos/tools/iverilog.py
CHANGED
|
@@ -136,6 +136,11 @@ class CommandSimIverilog(CommandSim, ToolIverilog):
|
|
|
136
136
|
# +define+{k}={v}, but also for SystemVerilog plusargs
|
|
137
137
|
command_list += [ '-D', f'{k}={sanitize_defines_for_sh(v)}' ]
|
|
138
138
|
|
|
139
|
+
# parameters
|
|
140
|
+
command_list.extend(
|
|
141
|
+
self.process_parameters_get_list(arg_prefix=f'-P{self.args["top"]}.')
|
|
142
|
+
)
|
|
143
|
+
|
|
139
144
|
if not self.files_sv and not self.files_v:
|
|
140
145
|
if not self.args['stop-before-compile']:
|
|
141
146
|
self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
|
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
|
|
|
@@ -94,7 +94,8 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
94
94
|
return
|
|
95
95
|
if self.args['stop-after-compile']:
|
|
96
96
|
vsim_command_lists = self.get_compile_command_lists()
|
|
97
|
-
self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log'
|
|
97
|
+
self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log',
|
|
98
|
+
must_strings=['Errors: 0'], use_must_strings=False)
|
|
98
99
|
|
|
99
100
|
def elaborate(self):
|
|
100
101
|
if self.args['stop-before-compile']:
|
|
@@ -200,6 +201,44 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
200
201
|
with open(vlog_dot_f_fpath, 'w', encoding='utf-8') as f:
|
|
201
202
|
f.writelines(line + "\n" for line in vlog_dot_f_lines)
|
|
202
203
|
|
|
204
|
+
def vopt_handle_parameters(self) -> (str, list):
|
|
205
|
+
'''Returns str for vopt or voptargs, and list of vopt tcl
|
|
206
|
+
|
|
207
|
+
Note this is used for self.use_vopt = True or False.
|
|
208
|
+
'''
|
|
209
|
+
|
|
210
|
+
voptargs_str = ''
|
|
211
|
+
vopt_do_lines = []
|
|
212
|
+
|
|
213
|
+
# Note that if self.use_vopt=True, we have to do some workarounds for how
|
|
214
|
+
# some questa-like tools behave for: tcl/.do + vopt arg processing
|
|
215
|
+
# This affects string based parameters that have spaces (vopt treats spaces unique args,
|
|
216
|
+
# vsim does not). Since we'd like to keep the vopt/vsim split into separate steps, we can
|
|
217
|
+
# work around this by setting tcl varaibles for each parameter.
|
|
218
|
+
if self.parameters:
|
|
219
|
+
if not self.use_vopt:
|
|
220
|
+
voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
|
|
221
|
+
else:
|
|
222
|
+
for k,v in self.parameters.items():
|
|
223
|
+
s = sim.parameters_dict_get_command_list(params={k: v}, arg_prefix='')[0]
|
|
224
|
+
# At this point, s should be a str in form {k}={v}
|
|
225
|
+
if not s or '=' not in s:
|
|
226
|
+
continue
|
|
227
|
+
if ' ' in s:
|
|
228
|
+
# Instead of:
|
|
229
|
+
# vopt -GMyParam="hi bye"
|
|
230
|
+
# we'll do:
|
|
231
|
+
# set PARAMETERS(MyParam) "hi bye"
|
|
232
|
+
# vopt -GMyParam=$PARAMETERS(MyParam)
|
|
233
|
+
s = s.replace(f'{k}=', f'set PARAMETERS({k}) ')
|
|
234
|
+
vopt_do_lines.append(s)
|
|
235
|
+
voptargs_str += f' -G{k}=$PARAMETERS({k}) '
|
|
236
|
+
else:
|
|
237
|
+
voptargs_str += f' -G{s} '
|
|
238
|
+
|
|
239
|
+
return voptargs_str, vopt_do_lines
|
|
240
|
+
|
|
241
|
+
|
|
203
242
|
def write_vsim_dot_do( # pylint: disable=too-many-locals
|
|
204
243
|
self, dot_do_to_write: list
|
|
205
244
|
) -> None:
|
|
@@ -222,6 +261,14 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
222
261
|
typ='waveform', description='Modelsim/Questa Waveform WLF (Wave Log Format) file'
|
|
223
262
|
)
|
|
224
263
|
|
|
264
|
+
vlog_do_lines = []
|
|
265
|
+
vsim_do_lines = []
|
|
266
|
+
|
|
267
|
+
# parameters, use helper method to get voptargs_str and vopt_do_lines
|
|
268
|
+
more_voptargs_str, vopt_do_lines = self.vopt_handle_parameters()
|
|
269
|
+
voptargs_str += more_voptargs_str
|
|
270
|
+
|
|
271
|
+
|
|
225
272
|
# TODO(drew): support self.args['sim_libary', 'elab-args', sim-args'] (3 lists)
|
|
226
273
|
# to add to vsim_one_liner.
|
|
227
274
|
|
|
@@ -246,7 +293,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
246
293
|
|
|
247
294
|
vsim_one_liner = vsim_one_liner.replace('\n', ' ')
|
|
248
295
|
|
|
249
|
-
vlog_do_lines
|
|
296
|
+
vlog_do_lines += [
|
|
250
297
|
"if {[file exists work]} { vdel -all work; }",
|
|
251
298
|
"vlib work;",
|
|
252
299
|
"quietly set qc 30;",
|
|
@@ -258,9 +305,8 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
258
305
|
"}",
|
|
259
306
|
]
|
|
260
307
|
|
|
261
|
-
vopt_do_lines = []
|
|
262
308
|
if self.use_vopt:
|
|
263
|
-
vopt_do_lines
|
|
309
|
+
vopt_do_lines += [
|
|
264
310
|
"if {[catch { " + vopt_one_liner + " } result] } {",
|
|
265
311
|
" echo \"Caught $result\";",
|
|
266
312
|
" if {[batch_mode]} {",
|
|
@@ -269,7 +315,7 @@ class CommandSimModelsimAse(CommandSim, ToolModelsimAse):
|
|
|
269
315
|
"}",
|
|
270
316
|
]
|
|
271
317
|
|
|
272
|
-
vsim_do_lines
|
|
318
|
+
vsim_do_lines += [
|
|
273
319
|
"if {[catch { " + vsim_one_liner + " } result] } {",
|
|
274
320
|
" echo \"Caught $result\";",
|
|
275
321
|
" if {[batch_mode]} {",
|
opencos/tools/quartus.py
CHANGED
|
@@ -19,6 +19,7 @@ from opencos.eda_base import Tool
|
|
|
19
19
|
from opencos.commands import (
|
|
20
20
|
CommandSynth, CommandBuild, CommandFList, CommandProj, CommandUpload, CommandOpen
|
|
21
21
|
)
|
|
22
|
+
from opencos.utils.str_helpers import sanitize_defines_for_sh, strip_outer_quotes
|
|
22
23
|
|
|
23
24
|
class ToolQuartus(Tool):
|
|
24
25
|
'''ToolQuartus used by opencos.eda for --tool=quartus'''
|
|
@@ -225,6 +226,18 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
225
226
|
for incdir in self.incdirs:
|
|
226
227
|
tcl_lines.append(f"set_global_assignment -name SEARCH_PATH \"{incdir}\"")
|
|
227
228
|
|
|
229
|
+
# Parameters --> set_parameter -name <Parameter_Name> <Value>
|
|
230
|
+
for k,v in self.parameters.items():
|
|
231
|
+
if not isinstance(v, (int, str)):
|
|
232
|
+
util.warning(f'parameter {k} has value: {v}, parameters must be int/string types')
|
|
233
|
+
if isinstance(v, int):
|
|
234
|
+
tcl_lines.append(f"set_parameter -name {k} {v}")
|
|
235
|
+
else:
|
|
236
|
+
v = strip_outer_quotes(v.strip('\n'))
|
|
237
|
+
v = '"' + v + '"'
|
|
238
|
+
tcl_lines.append(f"set_parameter -name {k} {sanitize_defines_for_sh(v)}")
|
|
239
|
+
|
|
240
|
+
|
|
228
241
|
# Add all include directories as user libraries for better include resolution
|
|
229
242
|
for incdir in self.incdirs:
|
|
230
243
|
if os.path.exists(incdir):
|
|
@@ -307,7 +320,7 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
307
320
|
'flow-tcl-files': [],
|
|
308
321
|
})
|
|
309
322
|
|
|
310
|
-
def do_it(self) -> None: # pylint: disable=too-many-branches,too-many-statements
|
|
323
|
+
def do_it(self) -> None: # pylint: disable=too-many-branches,too-many-statements,too-many-locals
|
|
311
324
|
# add defines for this job
|
|
312
325
|
self.set_tool_defines()
|
|
313
326
|
self.write_eda_config_and_args()
|
|
@@ -340,15 +353,25 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
340
353
|
# create an eda.flist_input.f that we'll pass to flist:
|
|
341
354
|
with open(os.path.join(self.args['work-dir'], 'eda.flist_input.f'),
|
|
342
355
|
'w', encoding='utf-8') as f:
|
|
356
|
+
|
|
357
|
+
# defines
|
|
358
|
+
for key,value in self.defines.items():
|
|
359
|
+
if value is None:
|
|
360
|
+
f.write(f"+define+{key}\n")
|
|
361
|
+
else:
|
|
362
|
+
f.write(shlex.quote(f"+define+{key}={value}") + "\n")
|
|
363
|
+
|
|
364
|
+
# incdirs:
|
|
365
|
+
for incdir in self.incdirs:
|
|
366
|
+
f.write(f'+incdir+{incdir}\n')
|
|
367
|
+
|
|
368
|
+
# files:
|
|
343
369
|
f.write('\n'.join(self.files_v + self.files_sv + self.files_vhd + ['']))
|
|
370
|
+
|
|
371
|
+
|
|
344
372
|
command_list.append('--input-file=eda.flist_input.f')
|
|
345
373
|
|
|
346
374
|
|
|
347
|
-
for key,value in self.defines.items():
|
|
348
|
-
if value is None:
|
|
349
|
-
command_list += [ f"+define+{key}" ]
|
|
350
|
-
else:
|
|
351
|
-
command_list += [ shlex.quote(f"+define+{key}={value}") ]
|
|
352
375
|
|
|
353
376
|
# Write out a .sh command for debug
|
|
354
377
|
command_list = util.ShellCommandList(command_list, tee_fpath='run_eda_flist.log')
|
|
@@ -487,6 +510,9 @@ class CommandFListQuartus(CommandFList, ToolQuartus):
|
|
|
487
510
|
def __init__(self, config: dict):
|
|
488
511
|
CommandFList.__init__(self, config=config)
|
|
489
512
|
ToolQuartus.__init__(self, config=self.config)
|
|
513
|
+
self.args.update({
|
|
514
|
+
'emit-parameter': False
|
|
515
|
+
})
|
|
490
516
|
|
|
491
517
|
|
|
492
518
|
class CommandProjQuartus(CommandProj, ToolQuartus):
|
opencos/tools/riviera.py
CHANGED
|
@@ -74,6 +74,17 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
74
74
|
# Note: many of these we follow the same flow as CommandSimModelsimAse:
|
|
75
75
|
# do_it, prepare_compile, compile, elaborate, simulate
|
|
76
76
|
|
|
77
|
+
def compile(self):
|
|
78
|
+
'''Override for CommandSimModelsimAse.compile() so we can set our own must_strings'''
|
|
79
|
+
if self.args['stop-before-compile']:
|
|
80
|
+
# don't run anything, save everyting we've already run in _prep_compile()
|
|
81
|
+
return
|
|
82
|
+
if self.args['stop-after-compile']:
|
|
83
|
+
vsim_command_lists = self.get_compile_command_lists()
|
|
84
|
+
self.run_commands_check_logs(vsim_command_lists, log_filename='sim.log',
|
|
85
|
+
must_strings=['Compile success 0 Errors'],
|
|
86
|
+
use_must_strings=False)
|
|
87
|
+
|
|
77
88
|
def get_compile_command_lists(self, **kwargs) -> list:
|
|
78
89
|
# This will also set up a compile.
|
|
79
90
|
vsim_command_list = [
|
|
@@ -128,7 +139,6 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
128
139
|
if v is None:
|
|
129
140
|
vlog_dot_f_lines += [ f'+define+{k}' ]
|
|
130
141
|
else:
|
|
131
|
-
|
|
132
142
|
# if the value v is a double-quoted string, such as v='"hi"', the
|
|
133
143
|
# entire +define+NAME="hi" needs to wrapped in double quotes with the
|
|
134
144
|
# value v double-quotes escaped: "+define+NAME=\"hi\""
|
|
@@ -170,11 +180,15 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
170
180
|
|
|
171
181
|
voptargs_str = ""
|
|
172
182
|
if self.args['gui'] or self.args['waves'] or self.args['coverage']:
|
|
173
|
-
voptargs_str
|
|
174
|
-
|
|
183
|
+
voptargs_str += self.tool_config.get('simulate-waves-args',
|
|
184
|
+
'+accb +accr +access +r+w')
|
|
175
185
|
if self.args['coverage']:
|
|
176
186
|
voptargs_str += self.tool_config.get('coverage-args', '')
|
|
177
187
|
|
|
188
|
+
# parameters
|
|
189
|
+
if self.parameters:
|
|
190
|
+
voptargs_str += ' ' + ' '.join(self.process_parameters_get_list(arg_prefix='-G'))
|
|
191
|
+
|
|
178
192
|
# TODO(drew): support self.args['sim_libary', 'elab-args', sim-args'] (3 lists)
|
|
179
193
|
# to add to vsim_one_liner.
|
|
180
194
|
|
opencos/tools/slang.py
CHANGED
|
@@ -143,6 +143,11 @@ class CommandElabSlang(CommandElab, ToolSlang):
|
|
|
143
143
|
# --define-macro {k}={v}
|
|
144
144
|
command_list.append( f'{k}={sanitize_defines_for_sh(v)}' )
|
|
145
145
|
|
|
146
|
+
# parameters
|
|
147
|
+
command_list.extend(
|
|
148
|
+
self.process_parameters_get_list(arg_prefix='-G ')
|
|
149
|
+
)
|
|
150
|
+
|
|
146
151
|
# Because many elab target-name won't match the --top needed for
|
|
147
152
|
# slang, we'll leave this to arg --slang-top:
|
|
148
153
|
if self.args.get('slang-top', None):
|
opencos/tools/slang_yosys.py
CHANGED
|
@@ -10,6 +10,8 @@ import os
|
|
|
10
10
|
from opencos import util
|
|
11
11
|
from opencos.tools.yosys import ToolYosys, CommonSynthYosys, CommandLecYosys
|
|
12
12
|
|
|
13
|
+
from opencos.commands.sim import parameters_dict_get_command_list
|
|
14
|
+
|
|
13
15
|
class ToolSlangYosys(ToolYosys):
|
|
14
16
|
'''Uses slang.so in yosys plugins directory, called via yosys > plugin -i slang'''
|
|
15
17
|
_TOOL = 'slang_yosys'
|
|
@@ -109,7 +111,17 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
109
111
|
]
|
|
110
112
|
|
|
111
113
|
read_slang_cmd += self.get_yosys_read_verilog_defines_incdirs_files()
|
|
112
|
-
|
|
114
|
+
|
|
115
|
+
# For slang step, need to resolve parameters too. We do NOT do this on
|
|
116
|
+
# subsquent yosys read_verilog steps.
|
|
117
|
+
read_slang_cmd += parameters_dict_get_command_list(
|
|
118
|
+
params=self.parameters, arg_prefix='-G '
|
|
119
|
+
)
|
|
120
|
+
|
|
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
|
+
|
|
113
125
|
return ' '.join(read_slang_cmd)
|
|
114
126
|
|
|
115
127
|
|
opencos/tools/surelog.py
CHANGED
|
@@ -109,6 +109,11 @@ class CommandElabSurelog(CommandElab, ToolSurelog):
|
|
|
109
109
|
for value in self.incdirs:
|
|
110
110
|
command_list.append('+incdir+' + value)
|
|
111
111
|
|
|
112
|
+
# parameters
|
|
113
|
+
command_list.extend(
|
|
114
|
+
self.process_parameters_get_list(arg_prefix='-P')
|
|
115
|
+
)
|
|
116
|
+
|
|
112
117
|
# defines:
|
|
113
118
|
for k,v in self.defines.items():
|
|
114
119
|
if v is None:
|
opencos/tools/verilator.py
CHANGED
|
@@ -244,6 +244,11 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
244
244
|
# +define+{k}={v}, but also for SystemVerilog plusargs
|
|
245
245
|
verilate_command_list += [ f'+define+{k}={sanitize_defines_for_sh(v)}' ]
|
|
246
246
|
|
|
247
|
+
# parameters
|
|
248
|
+
verilate_command_list.extend(
|
|
249
|
+
self.process_parameters_get_list(arg_prefix='-G')
|
|
250
|
+
)
|
|
251
|
+
|
|
247
252
|
if not self.files_sv and not self.files_v:
|
|
248
253
|
if not self.args['stop-before-compile']:
|
|
249
254
|
self.error(f'{self.target=} {self.files_sv=} and {self.files_v=} are empty,',
|
opencos/tools/vivado.py
CHANGED
|
@@ -22,6 +22,9 @@ from opencos.eda_base import Tool
|
|
|
22
22
|
from opencos.commands import CommandSim, CommandSynth, CommandProj, CommandBuild, \
|
|
23
23
|
CommandFList, CommandUpload, CommandOpen
|
|
24
24
|
|
|
25
|
+
from opencos.commands import sim
|
|
26
|
+
|
|
27
|
+
|
|
25
28
|
class ToolVivado(Tool):
|
|
26
29
|
'''ToolVivado used by opencos.eda for --tool=vivado'''
|
|
27
30
|
|
|
@@ -214,6 +217,12 @@ class CommandSimVivado(CommandSim, ToolVivado):
|
|
|
214
217
|
command_list[0] += ".bat"
|
|
215
218
|
command_list += self.tool_config.get('elab-args',
|
|
216
219
|
'-s snapshot -timescale 1ns/1ps --stats').split()
|
|
220
|
+
|
|
221
|
+
# parameters
|
|
222
|
+
command_list.extend(
|
|
223
|
+
self.process_parameters_get_list(arg_prefix='-generic_top ')
|
|
224
|
+
)
|
|
225
|
+
|
|
217
226
|
if self.tool_config.get('elab-waves-args', ''):
|
|
218
227
|
command_list += self.tool_config.get('elab-waves-args', '').split()
|
|
219
228
|
elif self.args['gui'] and self.args['waves']:
|
|
@@ -412,6 +421,9 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
|
|
|
412
421
|
defines = ""
|
|
413
422
|
for key, value in self.defines.items():
|
|
414
423
|
defines += (f"-verilog_define {key}" + (" " if value is None else f"={value} "))
|
|
424
|
+
parameters = ' '.join(
|
|
425
|
+
sim.parameters_dict_get_command_list(params=self.parameters, arg_prefix='-generic ')
|
|
426
|
+
)
|
|
415
427
|
incdirs = ' '.join([f'-include_dirs {x}' for x in self.incdirs])
|
|
416
428
|
flatten = ""
|
|
417
429
|
if self.args['flatten-all']:
|
|
@@ -457,10 +469,10 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
|
|
|
457
469
|
tcl_lines += [
|
|
458
470
|
"# FIRST PASS -- auto_detect_xpm",
|
|
459
471
|
"synth_design -rtl -rtl_skip_ip -rtl_skip_constraints -no_timing_driven -no_iobuf " \
|
|
460
|
-
+ f"-top {top} {incdirs} {defines} {v}",
|
|
472
|
+
+ f"-top {top} {incdirs} {defines} {parameters} {v}",
|
|
461
473
|
f"auto_detect_xpm {v} ",
|
|
462
474
|
f"synth_design -no_iobuf -part {part} {flatten} -constrset constraints_1 " \
|
|
463
|
-
+ f"-top {top} {incdirs} {defines} {v}",
|
|
475
|
+
+ f"-top {top} {incdirs} {defines} {parameters} {v}",
|
|
464
476
|
f"write_verilog -force {top}.vg {v}",
|
|
465
477
|
f"report_utilization -file {top}.flat.util.rpt {v}",
|
|
466
478
|
f"report_utilization -file {top}.hier.util.rpt {v} -hierarchical " \
|
|
@@ -753,6 +765,7 @@ class CommandFListVivado(CommandFList, ToolVivado):
|
|
|
753
765
|
CommandFList.__init__(self, config=config)
|
|
754
766
|
ToolVivado.__init__(self, config=self.config)
|
|
755
767
|
self.args['all-sv'] = False
|
|
768
|
+
self.args['emit-parameter'] = False
|
|
756
769
|
|
|
757
770
|
|
|
758
771
|
class CommandUploadVivado(CommandUpload, ToolVivado):
|
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
|
]
|