opencos-eda 0.2.44__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/lec.py +103 -0
- opencos/commands/shell.py +202 -0
- opencos/commands/sim.py +1 -1
- opencos/eda.py +2 -0
- opencos/eda_base.py +5 -3
- opencos/eda_config_defaults.yml +16 -5
- opencos/eda_extract_targets.py +13 -3
- opencos/tests/helpers.py +2 -1
- opencos/tests/test_deps_schema.py +3 -1
- opencos/tests/test_eda.py +19 -9
- opencos/tools/invio_yosys.py +7 -7
- opencos/tools/slang_yosys.py +29 -38
- opencos/tools/tabbycad_yosys.py +1 -1
- opencos/tools/vivado.py +8 -7
- opencos/tools/yosys.py +433 -12
- opencos/util.py +14 -6
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.45.dist-info}/METADATA +1 -1
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.45.dist-info}/RECORD +24 -22
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.45.dist-info}/WHEEL +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.45.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.45.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.45.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.2.44.dist-info → opencos_eda-0.2.45.dist-info}/top_level.txt +0 -0
opencos/tools/yosys.py
CHANGED
|
@@ -10,8 +10,31 @@ import shutil
|
|
|
10
10
|
import subprocess
|
|
11
11
|
|
|
12
12
|
from opencos import util
|
|
13
|
-
from opencos.eda_base import Tool
|
|
14
|
-
from opencos.commands import CommandSynth
|
|
13
|
+
from opencos.eda_base import Tool, get_eda_exec
|
|
14
|
+
from opencos.commands import CommandSynth, CommandLec
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_commands_to_run_scriptfiles(
|
|
18
|
+
script_fnames_list: list, yosys_exe: str
|
|
19
|
+
) -> [util.ShellCommandList]:
|
|
20
|
+
'''Checks file existence and returns list of commands to run a
|
|
21
|
+
|
|
22
|
+
list of yoysys script(s)'''
|
|
23
|
+
|
|
24
|
+
if script_fnames_list:
|
|
25
|
+
return []
|
|
26
|
+
|
|
27
|
+
yosys_cmdlists = []
|
|
28
|
+
for i,fpath in enumerate(script_fnames_list):
|
|
29
|
+
if not os.path.isfile(fpath):
|
|
30
|
+
util.error(f'yosys-scriptfile={fpath} file does not exist')
|
|
31
|
+
cmdlist = util.ShellCommandList(
|
|
32
|
+
[yosys_exe, '--scriptfile', os.path.abspath(fpath)],
|
|
33
|
+
tee_fpath = f'yosys_scriptfile.{i}.log'
|
|
34
|
+
)
|
|
35
|
+
yosys_cmdlists.append(cmdlist)
|
|
36
|
+
return yosys_cmdlists
|
|
37
|
+
|
|
15
38
|
|
|
16
39
|
class ToolYosys(Tool):
|
|
17
40
|
'''Parent class for ToolTabbyCadYosys, ToolInvioYosys, ToolSlangYosys'''
|
|
@@ -80,7 +103,7 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
80
103
|
for child classes: CommandSynthInvioYosys and tabbycad_yosys.CommandSynthTabbyCadYosys
|
|
81
104
|
'''
|
|
82
105
|
|
|
83
|
-
def __init__(self, config:dict):
|
|
106
|
+
def __init__(self, config: dict):
|
|
84
107
|
CommandSynth.__init__(self, config=config)
|
|
85
108
|
ToolYosys.__init__(self, config=self.config)
|
|
86
109
|
|
|
@@ -91,6 +114,8 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
91
114
|
'yosys-synth': 'synth', # synth_xilinx, synth_altera, etc (see: yosys help)
|
|
92
115
|
'yosys-pre-synth': ['prep', 'proc'], # command run in yosys prior to yosys-synth.
|
|
93
116
|
'yosys-blackbox': [], # list of modules that yosys will blackbox.
|
|
117
|
+
'yosys-scriptfile': [],
|
|
118
|
+
'sta-scriptfile': [],
|
|
94
119
|
})
|
|
95
120
|
self.args_help.update({
|
|
96
121
|
'sta': (
|
|
@@ -114,6 +139,16 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
114
139
|
'List of modules that yosys will blackbox, likely will need these'
|
|
115
140
|
' in Verilog-2001 for yosys to read outside of slang and synth'
|
|
116
141
|
),
|
|
142
|
+
'yosys-scriptfile': (
|
|
143
|
+
'Instead of using a built-in flow from eda, use your own scripts that are called'
|
|
144
|
+
' via: yosys --scriptfile <this-arg>. You can set multiple args for multiple'
|
|
145
|
+
' scriptfile (appends)'
|
|
146
|
+
),
|
|
147
|
+
'sta-scriptfile': (
|
|
148
|
+
'Instead of using a built-in flow from eda, use your own script that is called'
|
|
149
|
+
' via: sta -no_init -exit <this-arg>. You can set multiple args for multiple'
|
|
150
|
+
' scriptfile (appends)'
|
|
151
|
+
),
|
|
117
152
|
})
|
|
118
153
|
|
|
119
154
|
self.yosys_out_dir = ''
|
|
@@ -138,16 +173,139 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
138
173
|
self.do_export()
|
|
139
174
|
return
|
|
140
175
|
|
|
141
|
-
self.
|
|
176
|
+
if self.args['yosys-scriptfile']:
|
|
177
|
+
yosys_cmdlists = self.get_commands_user_yosys_scriptfile()
|
|
178
|
+
sta_cmdlists = self.create_sta_f() # works for --sta w/out BYO scripts.
|
|
179
|
+
|
|
180
|
+
# We create a run_yosys.sh wrapping these scripts, but we do not run this one.
|
|
181
|
+
util.write_shell_command_file(
|
|
182
|
+
dirpath=self.args['work-dir'],
|
|
183
|
+
filename='run_yosys.sh',
|
|
184
|
+
command_lists=(yosys_cmdlists + sta_cmdlists)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# actually run it.
|
|
188
|
+
for x in yosys_cmdlists + sta_cmdlists:
|
|
189
|
+
if x:
|
|
190
|
+
self.exec(work_dir=self.full_work_dir, command_list=x,
|
|
191
|
+
tee_fpath=x.tee_fpath)
|
|
192
|
+
|
|
193
|
+
else:
|
|
194
|
+
self.write_and_run_yosys_f_files()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def get_commands_user_yosys_scriptfile(self) -> [util.ShellCommandList]:
|
|
198
|
+
'''Checks file existence and returns list of commands to run a
|
|
199
|
+
|
|
200
|
+
list of yoysys script(s)'''
|
|
201
|
+
cmd_lists = get_commands_to_run_scriptfiles(
|
|
202
|
+
script_fnames_list=self.args['yosys-scriptfile'],
|
|
203
|
+
yosys_exe=self.yosys_exe
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
if not cmd_lists:
|
|
207
|
+
util.error('Could not generate yosys commands for scripts',
|
|
208
|
+
f'{self.args["yosys-scriptfile"]}')
|
|
209
|
+
|
|
210
|
+
return cmd_lists
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def get_commands_user_sta_scriptfile(self) -> [util.ShellCommandList]:
|
|
214
|
+
'''Checks file existence and returns list of commands'''
|
|
215
|
+
if not self.args['sta-scriptfile']:
|
|
216
|
+
return []
|
|
217
|
+
|
|
218
|
+
ret_list = []
|
|
219
|
+
for i,fpath in enumerate(self.args['sta-scriptfile']):
|
|
220
|
+
if not os.path.isfile(fpath):
|
|
221
|
+
self.error(f'sta-scriptfile={fpath} file does not exist')
|
|
222
|
+
cmdlist = util.ShellCommandList(
|
|
223
|
+
[self.sta_exe, '-no_init', '-exit', os.path.abspath(fpath)],
|
|
224
|
+
tee_fpath = f'sta_scriptfile.{i}.log'
|
|
225
|
+
)
|
|
226
|
+
ret_list.append(cmdlist)
|
|
227
|
+
return ret_list
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def write_and_run_yosys_f_files(self) -> None:
|
|
231
|
+
'''Derived classes may override, to run remainder of do_it() steps
|
|
232
|
+
|
|
233
|
+
These built-ins do not use slang or another SV preprocessing step.
|
|
234
|
+
1. Creates and runs: yosys.synth.f
|
|
235
|
+
-- does blackboxing and synth steps
|
|
236
|
+
4. Creates a wrapper for human debug and reuse: yosys.f
|
|
237
|
+
'''
|
|
238
|
+
|
|
239
|
+
# Note - big assumption here that "module myname" is contained in myname.[v|sv]:
|
|
240
|
+
# we use both synth-blackbox and yosys-blackbox lists to blackbox modules in the
|
|
241
|
+
# yosys step (not in the slang step)
|
|
242
|
+
self.blackbox_list = self.args.get('yosys-blackbox', [])
|
|
243
|
+
self.blackbox_list += self.args.get('synth-blackbox', [])
|
|
244
|
+
|
|
245
|
+
# work-dir / yosys has already been created.
|
|
246
|
+
|
|
247
|
+
# Create and run yosys.synth.f
|
|
248
|
+
synth_command_list = self.create_yosys_synth_f() # util.ShellCommandList
|
|
249
|
+
|
|
250
|
+
# Optinally create and run a sta.f:
|
|
251
|
+
sta_command_lists = self.create_sta_f() # [] or [util.ShellCommandList]
|
|
252
|
+
|
|
253
|
+
# We create a run_yosys.sh wrapping these scripts, but we do not run this one.
|
|
254
|
+
util.write_shell_command_file(
|
|
255
|
+
dirpath=self.args['work-dir'],
|
|
256
|
+
filename='run_yosys.sh',
|
|
257
|
+
command_lists=[synth_command_list] + sta_command_lists,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# Do not run this if args['stop-before-compile'] is True
|
|
261
|
+
if self.args.get('stop-before-compile', False):
|
|
262
|
+
return
|
|
263
|
+
|
|
264
|
+
# Run the synth commands standalone:
|
|
265
|
+
self.exec(work_dir=self.full_work_dir, command_list=synth_command_list,
|
|
266
|
+
tee_fpath=synth_command_list.tee_fpath)
|
|
267
|
+
|
|
268
|
+
for x in sta_command_lists:
|
|
269
|
+
if self.args['sta'] and x:
|
|
270
|
+
self.exec(work_dir=self.full_work_dir, command_list=x,
|
|
271
|
+
tee_fpath=x.tee_fpath)
|
|
142
272
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
raise NotImplementedError
|
|
273
|
+
if self.status == 0:
|
|
274
|
+
util.info(f'yosys: wrote verilog to {self.yosys_v_path}')
|
|
146
275
|
|
|
147
276
|
|
|
148
277
|
def create_yosys_synth_f(self) -> util.ShellCommandList:
|
|
149
278
|
'''Derived classes may define, if they wish to get a list of yosys commands'''
|
|
150
|
-
|
|
279
|
+
|
|
280
|
+
# Create yosys.synth.f
|
|
281
|
+
yosys_synth_f_path = os.path.join(self.full_work_dir, 'yosys.synth.f')
|
|
282
|
+
|
|
283
|
+
# Since this assumes we didnt' run a SystemVerilog pre-processing step,
|
|
284
|
+
# read in all the verilog
|
|
285
|
+
yosys_blackbox_list = self.get_yosys_blackbox_list()
|
|
286
|
+
|
|
287
|
+
if self.args['liberty-file'] and not os.path.exists(self.args['liberty-file']):
|
|
288
|
+
self.error(f'--liberty-file={self.args["liberty-file"]} file does not exist')
|
|
289
|
+
|
|
290
|
+
with open(yosys_synth_f_path, 'w', encoding='utf-8') as f:
|
|
291
|
+
lines = [
|
|
292
|
+
self._get_read_verilog_one_liner()
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
if self.args['liberty-file']:
|
|
296
|
+
lines.append('read_liberty -lib ' + self.args['liberty-file'])
|
|
297
|
+
|
|
298
|
+
for inst in yosys_blackbox_list:
|
|
299
|
+
lines.append('blackbox ' + inst)
|
|
300
|
+
|
|
301
|
+
lines += self.get_synth_command_lines()
|
|
302
|
+
f.write('\n'.join(lines))
|
|
303
|
+
|
|
304
|
+
synth_command_list = util.ShellCommandList(
|
|
305
|
+
[self.yosys_exe, '--scriptfile', 'yosys.synth.f'],
|
|
306
|
+
tee_fpath = 'yosys.synth.log'
|
|
307
|
+
)
|
|
308
|
+
return synth_command_list
|
|
151
309
|
|
|
152
310
|
|
|
153
311
|
def get_synth_command_lines(self) -> list:
|
|
@@ -179,13 +337,25 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
179
337
|
]
|
|
180
338
|
return lines
|
|
181
339
|
|
|
340
|
+
def get_yosys_blackbox_list(self) -> list:
|
|
341
|
+
'''Returns blackbox list, since we don't have a preprocessing step like
|
|
182
342
|
|
|
183
|
-
|
|
343
|
+
slang, simply return self.blackbox_list. Intended to be overwritten by
|
|
344
|
+
derived classes so they can blackbox post-preprocessing.
|
|
345
|
+
'''
|
|
346
|
+
return self.blackbox_list
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def create_sta_f(self) -> [util.ShellCommandList]:
|
|
184
350
|
'''Returns command list, for running 'sta' on sta.f'''
|
|
185
351
|
|
|
186
352
|
if not self.args['sta']:
|
|
187
353
|
return []
|
|
188
354
|
|
|
355
|
+
if self.args['sta-scriptfile']:
|
|
356
|
+
# User brought one or more scriptfiles for STA, use those.
|
|
357
|
+
return self.get_commands_user_sta_scriptfile()
|
|
358
|
+
|
|
189
359
|
if not self.args['liberty-file']:
|
|
190
360
|
self.error('--sta is set, but need to also set --liberty-file=<file>')
|
|
191
361
|
|
|
@@ -228,10 +398,11 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
228
398
|
|
|
229
399
|
f.write('\n'.join(lines))
|
|
230
400
|
|
|
231
|
-
return
|
|
401
|
+
# return list with our one generated command-list
|
|
402
|
+
return [util.ShellCommandList(
|
|
232
403
|
sta_command_list,
|
|
233
|
-
tee_fpath =
|
|
234
|
-
)
|
|
404
|
+
tee_fpath = sta_command_list.tee_fpath
|
|
405
|
+
)]
|
|
235
406
|
|
|
236
407
|
|
|
237
408
|
def create_sdc_f(self) -> None:
|
|
@@ -256,3 +427,253 @@ class CommonSynthYosys(CommandSynth, ToolYosys):
|
|
|
256
427
|
+ ' [get_ports * -filter {DIRECTION == OUT}];',
|
|
257
428
|
]
|
|
258
429
|
f.write('\n'.join(lines))
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def _get_read_verilog_one_liner(self) -> str:
|
|
433
|
+
'''Returns a string, intended to be used w/out Slang, for Verilog or simple
|
|
434
|
+
|
|
435
|
+
SV designs'''
|
|
436
|
+
|
|
437
|
+
read_verilog_cmd = [
|
|
438
|
+
'read_verilog',
|
|
439
|
+
'-sv',
|
|
440
|
+
'-icells',
|
|
441
|
+
]
|
|
442
|
+
read_verilog_cmd += self.get_yosys_read_verilog_defines_incdirs_files()
|
|
443
|
+
read_verilog_cmd.append(f'--top {self.args["top"]}')
|
|
444
|
+
return ' '.join(read_verilog_cmd)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def get_yosys_read_verilog_defines_incdirs_files(self) -> list:
|
|
448
|
+
'''Returns a partial list of all the args for a read_verilog or read_slang command in yosys
|
|
449
|
+
|
|
450
|
+
Handles defines, incdirs, files_sv, files_v
|
|
451
|
+
'''
|
|
452
|
+
ret_list = []
|
|
453
|
+
|
|
454
|
+
for name,value in self.defines.items():
|
|
455
|
+
if not name:
|
|
456
|
+
continue
|
|
457
|
+
if name in ['SIMULATION']:
|
|
458
|
+
continue
|
|
459
|
+
|
|
460
|
+
if value is None:
|
|
461
|
+
ret_list.append(f'--define-macro {name}')
|
|
462
|
+
else:
|
|
463
|
+
ret_list.append(f'--define-macro {name}={value}')
|
|
464
|
+
|
|
465
|
+
# We must define SYNTHESIS for oclib_defines.vh to work correctly.
|
|
466
|
+
if 'SYNTHESIS' not in self.defines:
|
|
467
|
+
ret_list.append('--define-macro SYNTHESIS')
|
|
468
|
+
|
|
469
|
+
for path in self.incdirs:
|
|
470
|
+
ret_list.append(f'-I {path}')
|
|
471
|
+
|
|
472
|
+
for path in self.files_v:
|
|
473
|
+
ret_list.append(path)
|
|
474
|
+
|
|
475
|
+
for path in self.files_sv:
|
|
476
|
+
ret_list.append(path)
|
|
477
|
+
|
|
478
|
+
ret_list.append(f'--top {self.args["top"]}')
|
|
479
|
+
return ret_list
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
class CommandLecYosys(CommandLec, ToolYosys):
|
|
483
|
+
'''Command handler for: eda lec --designs=<target1> --designs=<target2> --tool=yosys
|
|
484
|
+
|
|
485
|
+
Also supports: eda lec --tool=yosys <target>
|
|
486
|
+
If the target sets two args for --designs
|
|
487
|
+
'''
|
|
488
|
+
|
|
489
|
+
def __init__(self, config: dict):
|
|
490
|
+
CommandLec.__init__(self, config=config)
|
|
491
|
+
ToolYosys.__init__(self, config=self.config)
|
|
492
|
+
|
|
493
|
+
self.args.update({
|
|
494
|
+
'yosys-scriptfile': [],
|
|
495
|
+
'pre-read-verilog': [],
|
|
496
|
+
})
|
|
497
|
+
self.args_help.update({
|
|
498
|
+
'yosys-scriptfile': (
|
|
499
|
+
'Instead of using a built-in flow from eda, use your own scripts that are called'
|
|
500
|
+
' via: yosys --scriptfile <this-arg>. You can set multiple args for multiple'
|
|
501
|
+
' scriptfile (appends)'
|
|
502
|
+
),
|
|
503
|
+
'pre-read-verilog': 'Additional verilog files to read prior to running LEC',
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
self.synth_work_dirs = [
|
|
507
|
+
os.path.join('eda.work', 'lec.design1.synth'),
|
|
508
|
+
os.path.join('eda.work', 'lec.design2.synth')
|
|
509
|
+
]
|
|
510
|
+
|
|
511
|
+
self.synth_designs_tops = [None, None]
|
|
512
|
+
self.synth_designs_fpaths = [None, None]
|
|
513
|
+
|
|
514
|
+
def get_synth_result_fpath(self, target: str) -> str:
|
|
515
|
+
'''Overridden from CommandLec'''
|
|
516
|
+
|
|
517
|
+
# Read the eda_output_config.yml, find the "top", and find the output .v filename.
|
|
518
|
+
return ""
|
|
519
|
+
|
|
520
|
+
def get_synth_command_list(self, design_num: int) -> list:
|
|
521
|
+
'''Returns one of the synthesis command lists, for design_num=0 or 1'''
|
|
522
|
+
|
|
523
|
+
if not design_num in [0, 1]:
|
|
524
|
+
self.error(f'{design_num=} we only support LEC on designs 0 and 1')
|
|
525
|
+
|
|
526
|
+
synth_cmd_list = [
|
|
527
|
+
get_eda_exec('synth'),
|
|
528
|
+
'synth',
|
|
529
|
+
]
|
|
530
|
+
|
|
531
|
+
if self.args['tool']:
|
|
532
|
+
synth_cmd_list.append('--tool=' + self.args['tool'])
|
|
533
|
+
|
|
534
|
+
synth_cmd_list += [
|
|
535
|
+
'--work-dir=' + self.synth_work_dirs[design_num],
|
|
536
|
+
self.args['designs'][design_num]
|
|
537
|
+
]
|
|
538
|
+
|
|
539
|
+
return synth_cmd_list
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def get_synth_top_from_output_config(self, design_num: int) -> str:
|
|
543
|
+
'''Returns the top name given the design number that we synthesized'''
|
|
544
|
+
|
|
545
|
+
work_dir = self.synth_work_dirs[design_num]
|
|
546
|
+
output_cfg_fpath = os.path.join(work_dir, util.EDA_OUTPUT_CONFIG_FNAME)
|
|
547
|
+
data = util.yaml_safe_load(output_cfg_fpath)
|
|
548
|
+
top = data.get('args', {}).get('top', '')
|
|
549
|
+
if not top:
|
|
550
|
+
self.error(f'"top" not found in synth run from {work_dir=} in',
|
|
551
|
+
f'config {output_cfg_fpath}')
|
|
552
|
+
return top
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def get_synth_results_fpath(self, design_num: int, top: str) -> str:
|
|
556
|
+
'''Returns the synthesized .v file fpath'''
|
|
557
|
+
if not top:
|
|
558
|
+
top = self.get_synth_top_from_output_config(design_num=design_num)
|
|
559
|
+
|
|
560
|
+
work_dir = self.synth_work_dirs[design_num]
|
|
561
|
+
fpath = os.path.join(work_dir, 'yosys', f'{top}.v')
|
|
562
|
+
if not os.path.isfile(fpath):
|
|
563
|
+
self.error(f'{fpath=} does not exists, looking for synth results for LEC {design_num=}')
|
|
564
|
+
return fpath
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def do_it(self) -> None:
|
|
568
|
+
self.set_tool_defines()
|
|
569
|
+
self.write_eda_config_and_args()
|
|
570
|
+
|
|
571
|
+
pwd = os.getcwd()
|
|
572
|
+
|
|
573
|
+
if not self.args['top']:
|
|
574
|
+
self.args['top'] = 'yosys_lec'
|
|
575
|
+
|
|
576
|
+
if self.args['yosys-scriptfile']:
|
|
577
|
+
yosys_cmdlists = get_commands_to_run_scriptfiles(
|
|
578
|
+
script_fnames_list=self.args['yosys-scriptfile'],
|
|
579
|
+
yosys_exe=self.yosys_exe
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
# We create a run_yosys.sh wrapping these scripts, but we do not run this one.
|
|
583
|
+
util.write_shell_command_file(
|
|
584
|
+
dirpath=self.args['work-dir'],
|
|
585
|
+
filename='run_yosys.sh',
|
|
586
|
+
command_lists=yosys_cmdlists
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
# actually run it.
|
|
590
|
+
for x in yosys_cmdlists:
|
|
591
|
+
if x:
|
|
592
|
+
self.exec(work_dir=self.args['work-dir'], command_list=x,
|
|
593
|
+
tee_fpath=x.tee_fpath)
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
if self.args['synth']:
|
|
597
|
+
synth1_cmd_list = self.get_synth_command_list(design_num=0)
|
|
598
|
+
synth2_cmd_list = self.get_synth_command_list(design_num=1)
|
|
599
|
+
|
|
600
|
+
util.info(f'LEC {synth1_cmd_list=}')
|
|
601
|
+
util.info(f'LEC {synth2_cmd_list=}')
|
|
602
|
+
|
|
603
|
+
self.exec(pwd, synth1_cmd_list, background=True)
|
|
604
|
+
util.info(f'Finished with 1st LEC synthesis {self.args["designs"][0]}')
|
|
605
|
+
|
|
606
|
+
self.exec(pwd, synth2_cmd_list, background=True)
|
|
607
|
+
util.info(f'Finished with 2nd LEC synthesis {self.args["designs"][1]}')
|
|
608
|
+
|
|
609
|
+
self.synth_designs_tops = [
|
|
610
|
+
self.get_synth_top_from_output_config(design_num=0),
|
|
611
|
+
self.get_synth_top_from_output_config(design_num=1)
|
|
612
|
+
]
|
|
613
|
+
util.info(f'Design tops: {self.synth_designs_tops}')
|
|
614
|
+
|
|
615
|
+
# read the output config
|
|
616
|
+
self.synth_designs_fpaths = [
|
|
617
|
+
os.path.abspath(
|
|
618
|
+
self.get_synth_results_fpath(design_num=0, top=self.synth_designs_tops[0])),
|
|
619
|
+
os.path.abspath(
|
|
620
|
+
self.get_synth_results_fpath(design_num=1, top=self.synth_designs_tops[1]))
|
|
621
|
+
]
|
|
622
|
+
util.info(f'Design tops: {self.synth_designs_fpaths}')
|
|
623
|
+
|
|
624
|
+
else:
|
|
625
|
+
# don't run synthesis, need the two top level .v files in
|
|
626
|
+
# self.synth_designs_fpaths, and need the two top module names in
|
|
627
|
+
# self.synth_designs_tops
|
|
628
|
+
self.synth_designs_fpaths = [
|
|
629
|
+
os.path.abspath(self.args['designs'][0]),
|
|
630
|
+
os.path.abspath(self.args['designs'][1])
|
|
631
|
+
]
|
|
632
|
+
|
|
633
|
+
path, fname = os.path.split(self.synth_designs_fpaths[0])
|
|
634
|
+
module_guess, _ = os.path.splitext(fname)
|
|
635
|
+
top1 = util.get_inferred_top_module_name(
|
|
636
|
+
module_guess=module_guess, module_fpath=self.synth_designs_fpaths[0]
|
|
637
|
+
)
|
|
638
|
+
util.info(f'design1 top module name = {top1} (from {path} / {fname})')
|
|
639
|
+
|
|
640
|
+
path, fname = os.path.split(self.synth_designs_fpaths[1])
|
|
641
|
+
module_guess, _ = os.path.splitext(fname)
|
|
642
|
+
top2 = util.get_inferred_top_module_name(
|
|
643
|
+
module_guess=module_guess, module_fpath=self.synth_designs_fpaths[1]
|
|
644
|
+
)
|
|
645
|
+
util.info(f'design2 top module name = {top2} (from {path} / {fname})')
|
|
646
|
+
|
|
647
|
+
self.synth_designs_tops = [top1, top2]
|
|
648
|
+
|
|
649
|
+
# Need to create final LEC yosys script, that reads our two designs and runs
|
|
650
|
+
# LEC. Note the designs must have different module names
|
|
651
|
+
if self.synth_designs_tops[0] == self.synth_designs_tops[1]:
|
|
652
|
+
self.error('Cannot run Yosys LEC on two designs with the same top module name:',
|
|
653
|
+
f'{self.synth_designs_tops}')
|
|
654
|
+
|
|
655
|
+
lec_cmd_f_list = []
|
|
656
|
+
if self.args['pre-read-verilog']:
|
|
657
|
+
for x in self.args['pre-read-verilog']:
|
|
658
|
+
if os.path.isfile(x):
|
|
659
|
+
lec_cmd_f_list += [
|
|
660
|
+
'read_verilog -sv -icells ' + os.path.abspath(x)
|
|
661
|
+
]
|
|
662
|
+
else:
|
|
663
|
+
self.error(f' --pre-read-verilog file {x} does not exist')
|
|
664
|
+
lec_cmd_f_list += [
|
|
665
|
+
f'read_verilog -sv -icells {self.synth_designs_fpaths[0]}',
|
|
666
|
+
f'read_verilog -sv -icells {self.synth_designs_fpaths[1]}',
|
|
667
|
+
'clk2fflogic;',
|
|
668
|
+
f'miter -equiv -flatten {" ".join(self.synth_designs_tops)} miter',
|
|
669
|
+
('sat -seq 50 -verify -prove trigger 0 -show-all -show-inputs -show-outputs'
|
|
670
|
+
' -set-init-zero miter'),
|
|
671
|
+
]
|
|
672
|
+
|
|
673
|
+
lec_cmd_f_fpath = os.path.join(self.args['work-dir'], 'yosys_lec.f')
|
|
674
|
+
with open(lec_cmd_f_fpath, 'w', encoding='utf-8') as f:
|
|
675
|
+
f.write('\n'.join(lec_cmd_f_list) + '\n')
|
|
676
|
+
|
|
677
|
+
lec_cmd_list = 'yosys --scriptfile yosys_lec.f'.split()
|
|
678
|
+
util.info(f'LEC running {lec_cmd_list}')
|
|
679
|
+
self.exec(self.args['work-dir'], lec_cmd_list)
|
opencos/util.py
CHANGED
|
@@ -23,6 +23,8 @@ logfile = None
|
|
|
23
23
|
loglast = 0
|
|
24
24
|
debug_level = 0
|
|
25
25
|
|
|
26
|
+
EDA_OUTPUT_CONFIG_FNAME = 'eda_output_config.yml'
|
|
27
|
+
|
|
26
28
|
args = {
|
|
27
29
|
'color' : False,
|
|
28
30
|
'quiet' : False,
|
|
@@ -614,7 +616,7 @@ def write_shell_command_file(dirpath : str, filename : str, command_lists : list
|
|
|
614
616
|
os.chmod(fullpath, 0o755)
|
|
615
617
|
|
|
616
618
|
|
|
617
|
-
def write_eda_config_and_args(dirpath : str, filename=
|
|
619
|
+
def write_eda_config_and_args(dirpath : str, filename=EDA_OUTPUT_CONFIG_FNAME, command_obj_ref=None):
|
|
618
620
|
import copy
|
|
619
621
|
if command_obj_ref is None:
|
|
620
622
|
return
|
|
@@ -653,7 +655,7 @@ def get_inferred_top_module_name(module_guess: str, module_fpath: str) -> str:
|
|
|
653
655
|
if line.startswith('module '):
|
|
654
656
|
parts = line.split()
|
|
655
657
|
module_name = parts[1]
|
|
656
|
-
rstrip_nonword_pattern = r'\W
|
|
658
|
+
rstrip_nonword_pattern = r'\W+.*$'
|
|
657
659
|
module_name = re.sub(rstrip_nonword_pattern, '', module_name)
|
|
658
660
|
if bool(re.fullmatch(r'^\w+$', module_name)):
|
|
659
661
|
if module_name == module_guess:
|
|
@@ -672,12 +674,14 @@ def subprocess_run(work_dir, command_list, fake:bool=False, shell=False) -> int:
|
|
|
672
674
|
if work_dir is not None:
|
|
673
675
|
os.chdir(work_dir)
|
|
674
676
|
|
|
677
|
+
is_windows = sys.platform.startswith('win')
|
|
678
|
+
|
|
675
679
|
proc_kwargs = {'shell': shell}
|
|
676
680
|
bash_exec = shutil.which('bash')
|
|
677
|
-
if shell and bash_exec:
|
|
681
|
+
if shell and bash_exec and not is_windows:
|
|
678
682
|
proc_kwargs.update({'executable': bash_exec})
|
|
679
683
|
|
|
680
|
-
if shell:
|
|
684
|
+
if not is_windows and shell:
|
|
681
685
|
c = ' '.join(command_list)
|
|
682
686
|
else:
|
|
683
687
|
c = command_list
|
|
@@ -698,6 +702,9 @@ def subprocess_run_background(work_dir, command_list, background=True, fake:bool
|
|
|
698
702
|
tee_fpath is relative to work_dir.
|
|
699
703
|
'''
|
|
700
704
|
|
|
705
|
+
|
|
706
|
+
is_windows = sys.platform.startswith('win')
|
|
707
|
+
|
|
701
708
|
debug(f'util.subprocess_run_background: {background=} {tee_fpath=} {shell=}')
|
|
702
709
|
|
|
703
710
|
if fake or (not background and not tee_fpath):
|
|
@@ -715,10 +722,11 @@ def subprocess_run_background(work_dir, command_list, background=True, fake:bool
|
|
|
715
722
|
}
|
|
716
723
|
|
|
717
724
|
bash_exec = shutil.which('bash')
|
|
718
|
-
if shell and bash_exec:
|
|
725
|
+
if shell and bash_exec and not is_windows:
|
|
726
|
+
# Note - windows powershell will end up calling: /bin/bash /c, which won't work
|
|
719
727
|
proc_kwargs.update({'executable': bash_exec})
|
|
720
728
|
|
|
721
|
-
if shell:
|
|
729
|
+
if not is_windows and shell:
|
|
722
730
|
c = ' '.join(command_list)
|
|
723
731
|
else:
|
|
724
732
|
c = command_list # leave as list.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.45
|
|
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
|
|
@@ -3,14 +3,14 @@ opencos/_version.py,sha256=qN7iBoOv-v4tEZz-Pu9sVUJwefshJOsgdaddn8HcHio,510
|
|
|
3
3
|
opencos/_waves_pkg.sv,sha256=1lbhQOVGc3t_R8czYjP40hssP0I3FlZOpHTkI7yKFbI,1251
|
|
4
4
|
opencos/deps_helpers.py,sha256=jIMYDp9BVwEl9gYUcVie19EHqO5-DRY-d-vSqaDKi4Y,56971
|
|
5
5
|
opencos/deps_schema.py,sha256=MhytzXwp071F14RwxqHt78ak8Qruoe4FeK5XSzkO2f0,14658
|
|
6
|
-
opencos/eda.py,sha256=
|
|
7
|
-
opencos/eda_base.py,sha256=
|
|
6
|
+
opencos/eda.py,sha256=Ky_Uc47TU1N6lRs06eatdpAvtgoSh0iXO0BxhSfEuk0,19420
|
|
7
|
+
opencos/eda_base.py,sha256=RY32yrUyUpGUaDN4y5SIv54osV57K4r9zs4lIGsYJCY,83784
|
|
8
8
|
opencos/eda_config.py,sha256=8wwX4PTZ5rmxWogrVxxqAY6adQFPxTsFkkTYbo6H4vU,8853
|
|
9
|
-
opencos/eda_config_defaults.yml,sha256=
|
|
9
|
+
opencos/eda_config_defaults.yml,sha256=7apbA6F0HS-9qC6pOiM128qDf29It0U_ZKxntYSuGUg,11525
|
|
10
10
|
opencos/eda_config_max_verilator_waivers.yml,sha256=lTAU4IOEbUWVlPzuer1YYhIyxpPINeA4EJqcRIT-Ymk,840
|
|
11
11
|
opencos/eda_config_reduced.yml,sha256=cQ9jY4J7EvAbeHTiP6bvpDSVJAYiitjLZPSxxLKIEbk,1440
|
|
12
12
|
opencos/eda_deps_bash_completion.bash,sha256=jMkQKY82HBgOnQeMdA1hMrXguRFtB52SMBxUemKovL4,1958
|
|
13
|
-
opencos/eda_extract_targets.py,sha256=
|
|
13
|
+
opencos/eda_extract_targets.py,sha256=QBvz-8N_Q4Fme92IgUubPhuHf4q4YY4bzTH4qo7I1jw,4385
|
|
14
14
|
opencos/eda_tool_helper.py,sha256=MxNd_ImyA13DZbzMol1R5H8tJZddJfqyDgFVR2ad374,1666
|
|
15
15
|
opencos/export_helper.py,sha256=sI-Kd9aCnlC_3y92Wv30uOjjstg-Emw7OiOWNy5j98M,19699
|
|
16
16
|
opencos/export_json_convert.py,sha256=KsP1ESmSWs8ouecDC5ikuwOFZNJtLjmiYOvYLeN5UZU,3768
|
|
@@ -20,16 +20,18 @@ opencos/oc_cli.py,sha256=kj2OXvgxli2WPj4MQ4zTBb36eFtsP2gsqDdeNeWGL4E,132108
|
|
|
20
20
|
opencos/pcie.py,sha256=VUJljaZJYgScAAx5yn7F6GoA8K9eTcw24otYZbkMpYs,3035
|
|
21
21
|
opencos/peakrdl_cleanup.py,sha256=vLhSOVs6cEzsi_PwAP4pSXu5_ZMZjDvfK_WmHDLbDac,486
|
|
22
22
|
opencos/seed.py,sha256=8TA2uXhBuT_lOaQdAKqdReYvfBWi_KuyQCFJzA2rOVM,549
|
|
23
|
-
opencos/util.py,sha256=
|
|
24
|
-
opencos/commands/__init__.py,sha256=
|
|
23
|
+
opencos/util.py,sha256=IH6yeazG5VI95I7lGDnn2U58QEYM5ozm3SOHh6rVD_s,29395
|
|
24
|
+
opencos/commands/__init__.py,sha256=DtOA56oWJu68l-_1_7Gdv0N-gtXVB3-p9IhGzAYex8U,1014
|
|
25
25
|
opencos/commands/build.py,sha256=jI5ul53qfwn6X-yfSdSQIcLBhGtzZUk7r_wKBBmKJI0,1425
|
|
26
26
|
opencos/commands/elab.py,sha256=m6Gk03wSzX8UkcmReooK7turF7LpqO0IcdOZwJ8XiyI,1596
|
|
27
27
|
opencos/commands/export.py,sha256=juzxJL5-RpEnU5DmwF0fiG5pUrB2BbUbvCp2OasEd88,3494
|
|
28
28
|
opencos/commands/flist.py,sha256=XO0JzNF4cEYlqoO6fJFEH-SjsqQtmIvDO-xRQL7wllY,8531
|
|
29
|
+
opencos/commands/lec.py,sha256=gN6nQ4GURhPC8nu8Zuj08s1fmNzuiuaS9vJgtNZyX28,3647
|
|
29
30
|
opencos/commands/multi.py,sha256=1IH5Bk5xnKsNvtEsYy8a6bFmcyHSfrMVK-lLNdj6vlg,26449
|
|
30
31
|
opencos/commands/open.py,sha256=unrpGckzg0FE5W3oARq8x0jX7hhV_uM9Oh5FgISHFAg,724
|
|
31
32
|
opencos/commands/proj.py,sha256=MdHTOtQYG93_gT97dWuSyAgUxX2vi9FRhL0dtc-rM98,1096
|
|
32
|
-
opencos/commands/
|
|
33
|
+
opencos/commands/shell.py,sha256=senuqSGOc5nVGU5voZNJO4_hzVAK0ELtu0wmRZgwv3k,7463
|
|
34
|
+
opencos/commands/sim.py,sha256=oZyc4thCWZAk4668bbehRBzbOOVQDhyoDyemlDwYPFg,14059
|
|
33
35
|
opencos/commands/sweep.py,sha256=O0VSpzHHlE_1hM-Edp4d80PAnh2P2HCIwsGLnhkRHWM,9107
|
|
34
36
|
opencos/commands/synth.py,sha256=quB-HWS4LKYTiFBHiYarQi4pMnRmt12wQTZpi14VvlE,4355
|
|
35
37
|
opencos/commands/targets.py,sha256=_jRNhm2Fqj0fmMvTw6Ba39DCsRHf_r_uZCy_R064kpA,1472
|
|
@@ -37,11 +39,11 @@ opencos/commands/upload.py,sha256=nlb4nlxrDCQPcabEmH3nP19g4PFILDqFDab4LwJ95Z4,79
|
|
|
37
39
|
opencos/commands/waves.py,sha256=SRfjfsqhuszXHylQrgqYiUT3a5CQs9doxJQzuV4Ae0w,7055
|
|
38
40
|
opencos/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
41
|
opencos/tests/custom_config.yml,sha256=TRoVM9ZFKPOA_8JmlpzaMhnGO1txmaD14N_8P1oqzew,257
|
|
40
|
-
opencos/tests/helpers.py,sha256=
|
|
42
|
+
opencos/tests/helpers.py,sha256=r4UYMckYzHY2i2RbSWvysOjerPhty_7i7RB-Z767M-c,8294
|
|
41
43
|
opencos/tests/test_build.py,sha256=FQAxOpLVQShAHD_L5rqJctPeSAoqoOCNFI0RXflLuY0,387
|
|
42
44
|
opencos/tests/test_deps_helpers.py,sha256=_nJSgLN6WVlMKqu6sCr29gjQyN3Jj-dVk8Ac64ygpJs,5928
|
|
43
|
-
opencos/tests/test_deps_schema.py,sha256=
|
|
44
|
-
opencos/tests/test_eda.py,sha256=
|
|
45
|
+
opencos/tests/test_deps_schema.py,sha256=T3P9KjaMyKsk8b7snNVvNSsom2hIJcg6Z9apYiXoH9Y,941
|
|
46
|
+
opencos/tests/test_eda.py,sha256=tplHcx4FiEn8Jmw1mJMlD6tGjpUJ6cxdBGiVRKo7Ykw,38809
|
|
45
47
|
opencos/tests/test_eda_elab.py,sha256=75bJpOaoO8rn1FXFxiE4KSu5FdjZP1IbW6SyTCjM_ao,2553
|
|
46
48
|
opencos/tests/test_eda_synth.py,sha256=kYfceUB0qQwQmN_lIJvXkHzwoILL3Yb59h3nImg0hLU,5235
|
|
47
49
|
opencos/tests/test_oc_cli.py,sha256=-ZmwVX_CPBXCGT9hXIBEr_XUSIGG2eky89YpSJIbRAg,731
|
|
@@ -56,22 +58,22 @@ opencos/tests/deps_files/test_err_fatal/DEPS.yml,sha256=GnXIUJvshQWR9PlYxX67T53e
|
|
|
56
58
|
opencos/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
59
|
opencos/tools/invio.py,sha256=q9E9n6xsozDfar-1rLvJEZbCpPb_bQEy6WKEI3KS3dk,3163
|
|
58
60
|
opencos/tools/invio_helpers.py,sha256=1au4CYmV5aC7DHjaZBNemydH6Eq0i-Yt5L3HyKfQOfY,7638
|
|
59
|
-
opencos/tools/invio_yosys.py,sha256=
|
|
61
|
+
opencos/tools/invio_yosys.py,sha256=asSjbdPjBXB76KxNZIhoDRn2DoXKsZEQ1YDX_WBzKiA,6019
|
|
60
62
|
opencos/tools/iverilog.py,sha256=ByWJdylcL0KewvO_5RJ0FU-fhgYvV_aW3cqNWipWdYI,6520
|
|
61
63
|
opencos/tools/modelsim_ase.py,sha256=d689U8aesv2jKSfRuyZtmWn246zi3bMfwZWyzS4DlFM,13327
|
|
62
64
|
opencos/tools/questa.py,sha256=AX_3USyf6eMcssH4b-8WLbCzz-cXYnQzlHvCyL9C7Og,7505
|
|
63
65
|
opencos/tools/riviera.py,sha256=m1ExBA3UHJCu7o-abCtlm_IAF6gj1W8arS8kXC0Qmn4,10682
|
|
64
66
|
opencos/tools/slang.py,sha256=Nw3_WaG88rQj4SYiXQqRY784iqOU7MnSdwz6tdz2Lio,7443
|
|
65
|
-
opencos/tools/slang_yosys.py,sha256=
|
|
67
|
+
opencos/tools/slang_yosys.py,sha256=3fyLRRdTXhSppNtUhhUl00oG-cT9TyyPTH6JvasS9ZE,9804
|
|
66
68
|
opencos/tools/surelog.py,sha256=XhxJCGt8hyligL0LNT1fCWkHF5pkt4WSp3eqVJlQ4uA,4998
|
|
67
|
-
opencos/tools/tabbycad_yosys.py,sha256=
|
|
69
|
+
opencos/tools/tabbycad_yosys.py,sha256=2LePPgYXBVdsy7YcffPIWN-I0B7queLQ_f_pme2SCGw,7803
|
|
68
70
|
opencos/tools/verilator.py,sha256=dWnoO8FUvjdMyFmuTjHvC_XYI_zwjApJApYy7iYubf0,18398
|
|
69
|
-
opencos/tools/vivado.py,sha256=
|
|
70
|
-
opencos/tools/yosys.py,sha256=
|
|
71
|
-
opencos_eda-0.2.
|
|
72
|
-
opencos_eda-0.2.
|
|
73
|
-
opencos_eda-0.2.
|
|
74
|
-
opencos_eda-0.2.
|
|
75
|
-
opencos_eda-0.2.
|
|
76
|
-
opencos_eda-0.2.
|
|
77
|
-
opencos_eda-0.2.
|
|
71
|
+
opencos/tools/vivado.py,sha256=_GVqKNIZt9CZeiXS5yZCWTFrhD3BKjcQfzhhxR1qLQM,40017
|
|
72
|
+
opencos/tools/yosys.py,sha256=FV43RcejyFir4B24WRShnzUoppJMK0sDDNkSlIX8Vew,25579
|
|
73
|
+
opencos_eda-0.2.45.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
74
|
+
opencos_eda-0.2.45.dist-info/licenses/LICENSE.spdx,sha256=8gn1610RMP6eFgT3Hm6q9VKXt0RvdTItL_oxMo72jII,189
|
|
75
|
+
opencos_eda-0.2.45.dist-info/METADATA,sha256=MNMQxXKjmHYdAEIike4YdzaCEQeaqld1hPo4GLQk8PY,604
|
|
76
|
+
opencos_eda-0.2.45.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
77
|
+
opencos_eda-0.2.45.dist-info/entry_points.txt,sha256=V8OE1lySAFcFQpDNJuVxVZteeSmDH-joLMhGvrxrvmg,164
|
|
78
|
+
opencos_eda-0.2.45.dist-info/top_level.txt,sha256=J4JDP-LpRyJqPNeh9bSjx6yrLz2Mk0h6un6YLmtqql4,8
|
|
79
|
+
opencos_eda-0.2.45.dist-info/RECORD,,
|
|
File without changes
|