opencos-eda 0.2.54__py3-none-any.whl → 0.2.56__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opencos/commands/__init__.py +2 -0
- opencos/commands/flist.py +10 -0
- opencos/commands/lint.py +51 -0
- opencos/commands/sim.py +31 -0
- opencos/deps/defaults.py +2 -0
- opencos/deps/deps_file.py +3 -1
- opencos/deps/deps_processor.py +39 -1
- opencos/deps_schema.py +22 -0
- opencos/eda.py +16 -5
- opencos/eda_base.py +108 -10
- opencos/eda_config.py +2 -1
- opencos/eda_config_defaults.yml +13 -1
- opencos/export_helper.py +15 -5
- opencos/hw/oc_cli.py +1 -1
- opencos/names.py +4 -1
- opencos/tests/helpers.py +5 -0
- opencos/tests/test_eda_elab.py +26 -5
- opencos/tests/test_eda_synth.py +12 -0
- opencos/tools/invio.py +8 -1
- opencos/tools/invio_helpers.py +47 -8
- opencos/tools/invio_yosys.py +3 -2
- opencos/tools/iverilog.py +18 -0
- opencos/tools/modelsim_ase.py +19 -1
- opencos/tools/quartus.py +93 -12
- opencos/tools/questa.py +14 -0
- opencos/tools/questa_fse.py +13 -0
- opencos/tools/riviera.py +30 -3
- opencos/tools/slang.py +17 -1
- opencos/tools/slang_yosys.py +9 -0
- opencos/tools/surelog.py +18 -0
- opencos/tools/verilator.py +19 -0
- opencos/tools/vivado.py +26 -2
- opencos/tools/yosys.py +15 -0
- opencos/util.py +7 -1
- opencos/utils/str_helpers.py +8 -4
- {opencos_eda-0.2.54.dist-info → opencos_eda-0.2.56.dist-info}/METADATA +2 -2
- {opencos_eda-0.2.54.dist-info → opencos_eda-0.2.56.dist-info}/RECORD +42 -41
- {opencos_eda-0.2.54.dist-info → opencos_eda-0.2.56.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.54.dist-info → opencos_eda-0.2.56.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.54.dist-info → opencos_eda-0.2.56.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.54.dist-info → opencos_eda-0.2.56.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.54.dist-info → opencos_eda-0.2.56.dist-info}/top_level.txt +0 -0
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'''
|
|
@@ -150,6 +151,7 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
150
151
|
self.write_tcl_file(tcl_file=tcl_file)
|
|
151
152
|
|
|
152
153
|
# execute Quartus synthesis
|
|
154
|
+
command_list_gui = [self.quartus_gui_exe, '-t', tcl_file]
|
|
153
155
|
command_list = [
|
|
154
156
|
self.quartus_exe, '-t', tcl_file
|
|
155
157
|
]
|
|
@@ -170,9 +172,27 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
170
172
|
typ='text', description='Quartus Synthesis Report'
|
|
171
173
|
)
|
|
172
174
|
|
|
173
|
-
self.
|
|
175
|
+
if self.args['gui'] and self.quartus_gui_exe:
|
|
176
|
+
self.exec(self.args['work-dir'], command_list_gui)
|
|
177
|
+
else:
|
|
178
|
+
self.exec(self.args['work-dir'], command_list)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
saved_qpf_filename = self.args["top"] + '.qpf'
|
|
182
|
+
if not os.path.isfile(os.path.join(self.args['work-dir'], saved_qpf_filename)):
|
|
183
|
+
self.error('Saved project file does not exist:',
|
|
184
|
+
os.path.join(self.args['work-dir'], saved_qpf_filename))
|
|
185
|
+
|
|
174
186
|
util.info(f"Synthesis done, results are in: {self.args['work-dir']}")
|
|
175
187
|
|
|
188
|
+
# Note: in GUI mode, if you ran: quaruts -t build.tcl, it will exit on completion,
|
|
189
|
+
# so we'll re-open the project.
|
|
190
|
+
if self.args['gui'] and self.quartus_gui_exe:
|
|
191
|
+
self.exec(
|
|
192
|
+
work_dir=self.args['work-dir'],
|
|
193
|
+
command_list=[self.quartus_gui_exe, saved_qpf_filename]
|
|
194
|
+
)
|
|
195
|
+
|
|
176
196
|
def write_tcl_file(self, tcl_file: str) -> None: # pylint: disable=too-many-locals,too-many-branches
|
|
177
197
|
'''Writes synthesis capable Quartus tcl file to filepath 'tcl_file'.'''
|
|
178
198
|
|
|
@@ -206,6 +226,18 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
206
226
|
for incdir in self.incdirs:
|
|
207
227
|
tcl_lines.append(f"set_global_assignment -name SEARCH_PATH \"{incdir}\"")
|
|
208
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
|
+
|
|
209
241
|
# Add all include directories as user libraries for better include resolution
|
|
210
242
|
for incdir in self.incdirs:
|
|
211
243
|
if os.path.exists(incdir):
|
|
@@ -221,11 +253,27 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
221
253
|
tcl_lines.append(f"set_global_assignment -name VERILOG_MACRO \"{key}={value}\"")
|
|
222
254
|
|
|
223
255
|
# Add constraints
|
|
256
|
+
default_sdc = False
|
|
257
|
+
sdc_files = []
|
|
224
258
|
if self.args['sdc']:
|
|
225
|
-
|
|
259
|
+
sdc_files = [os.path.abspath(self.args['sdc'])]
|
|
226
260
|
elif self.files_sdc:
|
|
227
|
-
|
|
228
|
-
|
|
261
|
+
# Use files from DEPS target or command line.
|
|
262
|
+
sdc_files = self.files_sdc
|
|
263
|
+
else:
|
|
264
|
+
default_sdc = True
|
|
265
|
+
sdc_file = self.args['top'] + '.sdc'
|
|
266
|
+
sdc_files = [sdc_file]
|
|
267
|
+
|
|
268
|
+
for f in sdc_files:
|
|
269
|
+
for attr in ('SDC_FILE', 'SYN_SDC_FILE', 'RTL_SDC_FILE'):
|
|
270
|
+
tcl_lines.extend([
|
|
271
|
+
f"set_global_assignment -name {attr} \"{f}\""
|
|
272
|
+
])
|
|
273
|
+
tcl_lines.append("set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON")
|
|
274
|
+
|
|
275
|
+
if default_sdc:
|
|
276
|
+
self.write_default_sdc(sdc_file=os.path.join(self.args['work-dir'], sdc_file))
|
|
229
277
|
|
|
230
278
|
tcl_lines += [
|
|
231
279
|
"# Run synthesis",
|
|
@@ -237,6 +285,25 @@ class CommandSynthQuartus(CommandSynth, ToolQuartus):
|
|
|
237
285
|
ftcl.write('\n'.join(tcl_lines))
|
|
238
286
|
|
|
239
287
|
|
|
288
|
+
def write_default_sdc(self, sdc_file: str) -> None:
|
|
289
|
+
'''Writes a default SDC file to filepath 'sdc_file'.'''
|
|
290
|
+
|
|
291
|
+
sdc_lines = []
|
|
292
|
+
util.info("Creating default constraints: clock:",
|
|
293
|
+
f"{self.args['clock-name']}, {self.args['clock-ns']} (ns),")
|
|
294
|
+
|
|
295
|
+
clock_name = self.args['clock-name']
|
|
296
|
+
period = self.args['clock-ns']
|
|
297
|
+
|
|
298
|
+
sdc_lines += [
|
|
299
|
+
("create_clock -name {" + clock_name + "} -period {" + str(period) + "} [get_ports "
|
|
300
|
+
"{" + clock_name + "}]")
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
with open( sdc_file, 'w', encoding='utf-8' ) as fsdc:
|
|
304
|
+
fsdc.write('\n'.join(sdc_lines))
|
|
305
|
+
|
|
306
|
+
|
|
240
307
|
class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
241
308
|
'''CommandBuildQuartus is a command handler for: eda build --tool=quartus'''
|
|
242
309
|
|
|
@@ -253,7 +320,7 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
253
320
|
'flow-tcl-files': [],
|
|
254
321
|
})
|
|
255
322
|
|
|
256
|
-
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
|
|
257
324
|
# add defines for this job
|
|
258
325
|
self.set_tool_defines()
|
|
259
326
|
self.write_eda_config_and_args()
|
|
@@ -286,15 +353,25 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
286
353
|
# create an eda.flist_input.f that we'll pass to flist:
|
|
287
354
|
with open(os.path.join(self.args['work-dir'], 'eda.flist_input.f'),
|
|
288
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:
|
|
289
369
|
f.write('\n'.join(self.files_v + self.files_sv + self.files_vhd + ['']))
|
|
370
|
+
|
|
371
|
+
|
|
290
372
|
command_list.append('--input-file=eda.flist_input.f')
|
|
291
373
|
|
|
292
374
|
|
|
293
|
-
for key,value in self.defines.items():
|
|
294
|
-
if value is None:
|
|
295
|
-
command_list += [ f"+define+{key}" ]
|
|
296
|
-
else:
|
|
297
|
-
command_list += [ shlex.quote(f"+define+{key}={value}") ]
|
|
298
375
|
|
|
299
376
|
# Write out a .sh command for debug
|
|
300
377
|
command_list = util.ShellCommandList(command_list, tee_fpath='run_eda_flist.log')
|
|
@@ -371,7 +448,8 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
371
448
|
util.write_shell_command_file(dirpath=self.args['work-dir'], filename='run_quartus_gui.sh',
|
|
372
449
|
command_lists=[
|
|
373
450
|
command_list_gui,
|
|
374
|
-
|
|
451
|
+
# reopen when done.
|
|
452
|
+
[self.quartus_gui_exe, saved_qpf_filename],
|
|
375
453
|
], line_breaks=True)
|
|
376
454
|
|
|
377
455
|
# Add artifact tracking for build
|
|
@@ -422,7 +500,7 @@ class CommandBuildQuartus(CommandBuild, ToolQuartus):
|
|
|
422
500
|
if self.args['gui'] and self.quartus_gui_exe:
|
|
423
501
|
self.exec(
|
|
424
502
|
work_dir=self.args['work-dir'],
|
|
425
|
-
command_list=[
|
|
503
|
+
command_list=[self.quartus_gui_exe, saved_qpf_filename]
|
|
426
504
|
)
|
|
427
505
|
|
|
428
506
|
|
|
@@ -432,6 +510,9 @@ class CommandFListQuartus(CommandFList, ToolQuartus):
|
|
|
432
510
|
def __init__(self, config: dict):
|
|
433
511
|
CommandFList.__init__(self, config=config)
|
|
434
512
|
ToolQuartus.__init__(self, config=self.config)
|
|
513
|
+
self.args.update({
|
|
514
|
+
'emit-parameter': False
|
|
515
|
+
})
|
|
435
516
|
|
|
436
517
|
|
|
437
518
|
class CommandProjQuartus(CommandProj, ToolQuartus):
|
opencos/tools/questa.py
CHANGED
|
@@ -267,7 +267,21 @@ class CommandFListQuesta(CommandFList, ToolQuesta):
|
|
|
267
267
|
class CommandElabQuesta(CommandSimQuesta):
|
|
268
268
|
'''Command handler for: eda elab --tool=questa'''
|
|
269
269
|
|
|
270
|
+
command_name = 'elab'
|
|
271
|
+
|
|
272
|
+
def __init__(self, config:dict):
|
|
273
|
+
CommandSimQuesta.__init__(self, config)
|
|
274
|
+
# add args specific to this simulator
|
|
275
|
+
self.args['stop-after-elaborate'] = True
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class CommandLintQuesta(CommandSimQuesta):
|
|
279
|
+
'''Command handler for: eda lint --tool=questa'''
|
|
280
|
+
|
|
281
|
+
command_name = 'lint'
|
|
282
|
+
|
|
270
283
|
def __init__(self, config:dict):
|
|
271
284
|
CommandSimQuesta.__init__(self, config)
|
|
272
285
|
# add args specific to this simulator
|
|
286
|
+
self.args['stop-after-compile'] = True
|
|
273
287
|
self.args['stop-after-elaborate'] = True
|
opencos/tools/questa_fse.py
CHANGED
|
@@ -56,8 +56,21 @@ class CommandSimQuestaFse(CommandSimModelsimAse):
|
|
|
56
56
|
class CommandElabQuestaFse(CommandSimQuestaFse):
|
|
57
57
|
'''CommandElabQuestaFse is a command handler for: eda elab --tool=questa_fse'''
|
|
58
58
|
|
|
59
|
+
command_name = 'elab'
|
|
60
|
+
|
|
61
|
+
def __init__(self, config:dict):
|
|
62
|
+
super().__init__(config)
|
|
63
|
+
self.args['stop-after-elaborate'] = True
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class CommandLintQuestaFse(CommandSimQuestaFse):
|
|
67
|
+
'''CommandLintQuestaFse is a command handler for: eda lint --tool=questa_fse'''
|
|
68
|
+
|
|
69
|
+
command_name = 'lint'
|
|
70
|
+
|
|
59
71
|
def __init__(self, config:dict):
|
|
60
72
|
super().__init__(config)
|
|
73
|
+
self.args['stop-after-compile'] = True
|
|
61
74
|
self.args['stop-after-elaborate'] = True
|
|
62
75
|
|
|
63
76
|
|
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
|
|
|
@@ -289,6 +303,19 @@ class CommandSimRiviera(CommandSimModelsimAse, ToolRiviera):
|
|
|
289
303
|
class CommandElabRiviera(CommandSimRiviera):
|
|
290
304
|
'''CommandElabRiviera is a command handler for: eda elab --tool=riviera'''
|
|
291
305
|
|
|
306
|
+
command_name = 'elab'
|
|
307
|
+
|
|
308
|
+
def __init__(self, config:dict):
|
|
309
|
+
super().__init__(config)
|
|
310
|
+
self.args['stop-after-elaborate'] = True
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class CommandLintRiviera(CommandSimRiviera):
|
|
314
|
+
'''CommandLintRiviera is a command handler for: eda lint --tool=riviera'''
|
|
315
|
+
|
|
316
|
+
command_name = 'lint'
|
|
317
|
+
|
|
292
318
|
def __init__(self, config:dict):
|
|
293
319
|
super().__init__(config)
|
|
320
|
+
self.args['stop-after-compile'] = True
|
|
294
321
|
self.args['stop-after-elaborate'] = True
|
opencos/tools/slang.py
CHANGED
|
@@ -115,7 +115,7 @@ class CommandElabSlang(CommandElab, ToolSlang):
|
|
|
115
115
|
pass
|
|
116
116
|
|
|
117
117
|
def elaborate(self):
|
|
118
|
-
''' elaborate() - following parent
|
|
118
|
+
''' elaborate() - following parent CommandSim's run() flow, runs slang_command_lists'''
|
|
119
119
|
if self.args['stop-before-compile'] or \
|
|
120
120
|
self.args['stop-after-compile']:
|
|
121
121
|
return
|
|
@@ -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):
|
|
@@ -208,3 +213,14 @@ class CommandElabSlang(CommandElab, ToolSlang):
|
|
|
208
213
|
)
|
|
209
214
|
|
|
210
215
|
return command_list
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class CommandLintSlang(CommandElabSlang):
|
|
219
|
+
'''CommandLintSlang is a command handler for: eda lint --tool=slang.'''
|
|
220
|
+
|
|
221
|
+
command_name = 'lint'
|
|
222
|
+
|
|
223
|
+
def __init__(self, config: dict):
|
|
224
|
+
super().__init__(config)
|
|
225
|
+
# keep stop-after-compile=False, allow's CommandElabSlang.elaborate() to run.
|
|
226
|
+
self.args['slang-args'] = ['--lint-only', '--ignore-unknown-modules']
|
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,6 +111,13 @@ class CommandSynthSlangYosys(CommonSynthYosys, ToolSlangYosys):
|
|
|
109
111
|
]
|
|
110
112
|
|
|
111
113
|
read_slang_cmd += self.get_yosys_read_verilog_defines_incdirs_files()
|
|
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
|
+
|
|
112
121
|
read_slang_cmd.append(f'--top {self.args["top"]}')
|
|
113
122
|
return ' '.join(read_slang_cmd)
|
|
114
123
|
|
opencos/tools/surelog.py
CHANGED
|
@@ -63,6 +63,7 @@ class CommandElabSurelog(CommandElab, ToolSurelog):
|
|
|
63
63
|
ToolSurelog.__init__(self, config=self.config)
|
|
64
64
|
self.args.update({
|
|
65
65
|
'surelog-top': '',
|
|
66
|
+
'surelog-args': [],
|
|
66
67
|
})
|
|
67
68
|
|
|
68
69
|
self.surelog_command_lists = []
|
|
@@ -98,6 +99,7 @@ class CommandElabSurelog(CommandElab, ToolSurelog):
|
|
|
98
99
|
'compile-args',
|
|
99
100
|
'-parse').split()
|
|
100
101
|
command_list += config_compile_args
|
|
102
|
+
command_list += self.args['surelog-args']
|
|
101
103
|
|
|
102
104
|
if util.args.get('debug', None) or \
|
|
103
105
|
util.args.get('verbose', None):
|
|
@@ -107,6 +109,11 @@ class CommandElabSurelog(CommandElab, ToolSurelog):
|
|
|
107
109
|
for value in self.incdirs:
|
|
108
110
|
command_list.append('+incdir+' + value)
|
|
109
111
|
|
|
112
|
+
# parameters
|
|
113
|
+
command_list.extend(
|
|
114
|
+
self.process_parameters_get_list(arg_prefix='-P')
|
|
115
|
+
)
|
|
116
|
+
|
|
110
117
|
# defines:
|
|
111
118
|
for k,v in self.defines.items():
|
|
112
119
|
if v is None:
|
|
@@ -139,3 +146,14 @@ class CommandElabSurelog(CommandElab, ToolSurelog):
|
|
|
139
146
|
dirpath=self.args['work-dir'], filename='run_surelog.sh',
|
|
140
147
|
command_lists=self.surelog_command_lists, line_breaks=True
|
|
141
148
|
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class CommandLintSurelog(CommandElabSurelog):
|
|
152
|
+
'''CommandLintSurelog is a command handler for: eda lint --tool=surelog.'''
|
|
153
|
+
command_name = 'lint'
|
|
154
|
+
|
|
155
|
+
def __init__(self, config: dict):
|
|
156
|
+
super().__init__(config)
|
|
157
|
+
# keep stop-after-compile=False, allow's CommandElabSurelog.elaborate() to run.
|
|
158
|
+
# run the "compile" step only for surelog by setting -noelab:
|
|
159
|
+
self.args['surelog-args'] = ['-noelab']
|
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,',
|
|
@@ -499,8 +504,22 @@ class VerilatorSim(CommandSim, ToolVerilator):
|
|
|
499
504
|
|
|
500
505
|
class VerilatorElab(VerilatorSim):
|
|
501
506
|
'''VerilatorElab is a command handler for: eda elab --tool=verilator'''
|
|
507
|
+
command_name = 'elab'
|
|
508
|
+
|
|
509
|
+
def __init__(self, config: dict):
|
|
510
|
+
super().__init__(config)
|
|
511
|
+
self.args['stop-after-elaborate'] = True
|
|
512
|
+
self.args['lint-only'] = True
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
class VerilatorLint(VerilatorSim):
|
|
516
|
+
'''VerilatorLint is a command handler for: eda lint --tool=verilator.
|
|
517
|
+
|
|
518
|
+
For practical reasons, this is identical to VerilatorElab with --stop-after-compile.'''
|
|
519
|
+
command_name = 'lint'
|
|
502
520
|
|
|
503
521
|
def __init__(self, config: dict):
|
|
504
522
|
super().__init__(config)
|
|
523
|
+
self.args['stop-after-compile'] = True
|
|
505
524
|
self.args['stop-after-elaborate'] = True
|
|
506
525
|
self.args['lint-only'] = True
|
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']:
|
|
@@ -347,9 +356,20 @@ class CommandSimVivado(CommandSim, ToolVivado):
|
|
|
347
356
|
|
|
348
357
|
class CommandElabVivado(CommandSimVivado):
|
|
349
358
|
'''CommandElabVivado is a command handler for: eda elab --tool=vivado, uses xvlog, xelab'''
|
|
359
|
+
command_name = 'elab'
|
|
360
|
+
def __init__(self, config: dict):
|
|
361
|
+
CommandSimVivado.__init__(self, config)
|
|
362
|
+
# add args specific to this tool
|
|
363
|
+
self.args['stop-after-elaborate'] = True
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class CommandLintVivado(CommandSimVivado):
|
|
367
|
+
'''CommandLintVivado is a command handler for: eda lint --tool=vivado, uses xvlog'''
|
|
368
|
+
command_name = 'lint'
|
|
350
369
|
def __init__(self, config: dict):
|
|
351
370
|
CommandSimVivado.__init__(self, config)
|
|
352
371
|
# add args specific to this tool
|
|
372
|
+
self.args['stop-after-compile'] = True
|
|
353
373
|
self.args['stop-after-elaborate'] = True
|
|
354
374
|
|
|
355
375
|
|
|
@@ -401,6 +421,9 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
|
|
|
401
421
|
defines = ""
|
|
402
422
|
for key, value in self.defines.items():
|
|
403
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
|
+
)
|
|
404
427
|
incdirs = ' '.join([f'-include_dirs {x}' for x in self.incdirs])
|
|
405
428
|
flatten = ""
|
|
406
429
|
if self.args['flatten-all']:
|
|
@@ -446,10 +469,10 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
|
|
|
446
469
|
tcl_lines += [
|
|
447
470
|
"# FIRST PASS -- auto_detect_xpm",
|
|
448
471
|
"synth_design -rtl -rtl_skip_ip -rtl_skip_constraints -no_timing_driven -no_iobuf " \
|
|
449
|
-
+ f"-top {top} {incdirs} {defines} {v}",
|
|
472
|
+
+ f"-top {top} {incdirs} {defines} {parameters} {v}",
|
|
450
473
|
f"auto_detect_xpm {v} ",
|
|
451
474
|
f"synth_design -no_iobuf -part {part} {flatten} -constrset constraints_1 " \
|
|
452
|
-
+ f"-top {top} {incdirs} {defines} {v}",
|
|
475
|
+
+ f"-top {top} {incdirs} {defines} {parameters} {v}",
|
|
453
476
|
f"write_verilog -force {top}.vg {v}",
|
|
454
477
|
f"report_utilization -file {top}.flat.util.rpt {v}",
|
|
455
478
|
f"report_utilization -file {top}.hier.util.rpt {v} -hierarchical " \
|
|
@@ -742,6 +765,7 @@ class CommandFListVivado(CommandFList, ToolVivado):
|
|
|
742
765
|
CommandFList.__init__(self, config=config)
|
|
743
766
|
ToolVivado.__init__(self, config=self.config)
|
|
744
767
|
self.args['all-sv'] = False
|
|
768
|
+
self.args['emit-parameter'] = False
|
|
745
769
|
|
|
746
770
|
|
|
747
771
|
class CommandUploadVivado(CommandUpload, ToolVivado):
|
opencos/tools/yosys.py
CHANGED
|
@@ -219,6 +219,9 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
219
219
|
if not self.args['sta-scriptfile']:
|
|
220
220
|
return []
|
|
221
221
|
|
|
222
|
+
# Add URL info for OpenSTA source code:
|
|
223
|
+
self._add_opensta_info()
|
|
224
|
+
|
|
222
225
|
ret_list = []
|
|
223
226
|
for i,fpath in enumerate(self.args['sta-scriptfile']):
|
|
224
227
|
if not os.path.isfile(fpath):
|
|
@@ -377,6 +380,9 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
377
380
|
if not self.sta_exe:
|
|
378
381
|
self.error(f'--sta is set, but "sta" was not found in PATH, see: {self._URL}')
|
|
379
382
|
|
|
383
|
+
# Add URL info for OpenSTA source code:
|
|
384
|
+
self._add_opensta_info()
|
|
385
|
+
|
|
380
386
|
sta_command_list = util.ShellCommandList(
|
|
381
387
|
[ self.sta_exe, '-no_init', '-exit', 'sta.f' ],
|
|
382
388
|
tee_fpath = 'sta.log'
|
|
@@ -439,6 +445,15 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
439
445
|
]
|
|
440
446
|
f.write('\n'.join(lines))
|
|
441
447
|
|
|
448
|
+
def _add_opensta_info(self) -> None:
|
|
449
|
+
'''Adds OpenSTA URL information to artifacts and logs'''
|
|
450
|
+
|
|
451
|
+
opensta_repo_url = 'https://github.com/The-OpenROAD-Project/OpenSTA'
|
|
452
|
+
|
|
453
|
+
# Log GPL3.0 license information
|
|
454
|
+
util.info(f'Using OpenSTA (see URL for license and source): {opensta_repo_url}')
|
|
455
|
+
if hasattr(self, 'sta_version') and self.sta_version:
|
|
456
|
+
util.info(f'OpenSTA version: {self.sta_version}')
|
|
442
457
|
|
|
443
458
|
def _get_read_verilog_one_liner(self) -> str:
|
|
444
459
|
'''Returns a string, intended to be used w/out Slang, for Verilog or simple
|
opencos/util.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'''opencos.util -- support global logging, argparser for printing (colors)'''
|
|
2
2
|
|
|
3
|
+
# pylint: disable=too-many-lines
|
|
4
|
+
|
|
3
5
|
import argparse
|
|
4
6
|
import atexit
|
|
5
7
|
import datetime
|
|
@@ -89,6 +91,7 @@ class ArtifactTypes(Enum):
|
|
|
89
91
|
TCL = 5
|
|
90
92
|
SHELL = 6
|
|
91
93
|
BITSTREAM = 7
|
|
94
|
+
LICENSE = 8
|
|
92
95
|
|
|
93
96
|
class Artifacts:
|
|
94
97
|
'''Class to hold file artifacts, for logs generated by EDA, or other artifcats created
|
|
@@ -198,7 +201,10 @@ class Artifacts:
|
|
|
198
201
|
# Update all file sizes:
|
|
199
202
|
remove_keys = set()
|
|
200
203
|
for key, entry in self.data.items():
|
|
201
|
-
if
|
|
204
|
+
if entry['type'] == 'license':
|
|
205
|
+
# License entries are metadata, not files - keep them as-is
|
|
206
|
+
entry['size'] = 0
|
|
207
|
+
elif os.path.isfile(entry['name']):
|
|
202
208
|
entry['size'] = os.path.getsize(entry['name'])
|
|
203
209
|
else:
|
|
204
210
|
# file doesn't exist, remove it from artifacts.
|
opencos/utils/str_helpers.py
CHANGED
|
@@ -7,14 +7,18 @@ import shlex
|
|
|
7
7
|
import textwrap
|
|
8
8
|
|
|
9
9
|
VALID_TARGET_INFO_STR = (
|
|
10
|
-
"should start with
|
|
10
|
+
"should start with a . or underscore/letter, rest should be"
|
|
11
|
+
" ., alpha-numeric, dashes, or underscores."
|
|
11
12
|
)
|
|
12
13
|
|
|
13
14
|
def is_valid_target_name(s: str) -> bool:
|
|
14
|
-
'''Returns True if str starts with underscore/letter, rest
|
|
15
|
-
|
|
15
|
+
'''Returns True if str starts with . or underscore/letter, rest alphanum, dash, dot,
|
|
16
|
+
|
|
17
|
+
or underscores. We allow '.' otherwise deps_file.py posts warnings about badly named
|
|
18
|
+
targets for files that are missing.'''
|
|
19
|
+
if not s or not (s[0].isalpha() or s[0] == '_' or s[0] == '.'):
|
|
16
20
|
return False
|
|
17
|
-
return s.replace('_', '').replace('-', '').isalnum()
|
|
21
|
+
return s.replace('_', '').replace('-', '').replace('.', '').isalnum()
|
|
18
22
|
|
|
19
23
|
def strip_all_quotes(s: str) -> str:
|
|
20
24
|
'''Returns str with all ' and " removed'''
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.56
|
|
4
4
|
Summary: A simple Python package for wrapping RTL simuliatons and synthesis
|
|
5
5
|
Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/cognichip/opencos
|
|
@@ -15,5 +15,5 @@ Requires-Dist: schema>=0.7.7
|
|
|
15
15
|
Requires-Dist: toml>=0.10.2
|
|
16
16
|
Requires-Dist: yamllint>=1.35.1
|
|
17
17
|
Requires-Dist: PySerial>=3.5
|
|
18
|
-
Requires-Dist: cocotb>=2.0
|
|
18
|
+
Requires-Dist: cocotb>=2.0
|
|
19
19
|
Dynamic: license-file
|