opencos-eda 0.2.44__py3-none-any.whl → 0.2.46__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/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.write_and_run_yosys_f_files()
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
- def write_and_run_yosys_f_files(self, **kwargs) -> None:
144
- '''Derived classes must define, to run remainder of do_it() steps'''
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
- return util.ShellCommandList([])
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
- def create_sta_f(self) -> util.ShellCommandList:
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 util.ShellCommandList(
401
+ # return list with our one generated command-list
402
+ return [util.ShellCommandList(
232
403
  sta_command_list,
233
- tee_fpath = 'sta.log'
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='eda_output_config.yml', command_obj_ref=None):
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.44
3
+ Version: 0.2.46
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
@@ -1,16 +1,16 @@
1
1
  opencos/__init__.py,sha256=ZQ7aOCbP0jkIMYGdVrb-mkZX3rnvaK8epBkmp506tXU,85
2
2
  opencos/_version.py,sha256=qN7iBoOv-v4tEZz-Pu9sVUJwefshJOsgdaddn8HcHio,510
3
3
  opencos/_waves_pkg.sv,sha256=1lbhQOVGc3t_R8czYjP40hssP0I3FlZOpHTkI7yKFbI,1251
4
- opencos/deps_helpers.py,sha256=jIMYDp9BVwEl9gYUcVie19EHqO5-DRY-d-vSqaDKi4Y,56971
5
- opencos/deps_schema.py,sha256=MhytzXwp071F14RwxqHt78ak8Qruoe4FeK5XSzkO2f0,14658
6
- opencos/eda.py,sha256=2xqCi6JlvRFbqCnqyonT9yXIibfOcmmKY4c_bsVgCkc,19260
7
- opencos/eda_base.py,sha256=oO7R1kPjZvOiCKoLQs9NrCpoZoVVKXSEVlYdBVzXuwk,83596
4
+ opencos/deps_helpers.py,sha256=Q49Su7cJdkcjC9PufE2EtveHYAuENe2F-Prpmlz7tcI,57245
5
+ opencos/deps_schema.py,sha256=-zXzU_l0mv8abaOgBcxmRiyIelZ9jOUBXI8ahf3ymBU,14860
6
+ opencos/eda.py,sha256=Ky_Uc47TU1N6lRs06eatdpAvtgoSh0iXO0BxhSfEuk0,19420
7
+ opencos/eda_base.py,sha256=utUTieQMv0RC2Mz5n8b7rtneKjSFI3YcgCiJON0T7Ws,84410
8
8
  opencos/eda_config.py,sha256=8wwX4PTZ5rmxWogrVxxqAY6adQFPxTsFkkTYbo6H4vU,8853
9
- opencos/eda_config_defaults.yml,sha256=yRZU0JHaBQj2_AeyS32RDnUBSLHp5et8RMImYuYOKqE,11177
9
+ opencos/eda_config_defaults.yml,sha256=AteZbwRJ6wviinks47-e5TX0DoU0culJfBw6L3xYOOA,11535
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=LLf8pGia0HxqXQFRck0E990EchbEdiFTC1fQyA8FZqs,4101
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=KfC0bPU_kA1_HvP27oLjRX27RajIOF9Heb_OxhZDhys,29079
24
- opencos/commands/__init__.py,sha256=d-8heMkBjjm6_yeduZgUv34lPfHVpj9MWP1ifpdjJws,916
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/sim.py,sha256=phATz_wR0BAH6B_IJ4zyzg_Hptp5hSEOe_-9NLaL_bY,14058
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=UhQd7eLsK2sYn97us_Bz6PT6lEqOxa5swCx9OMI1Ffc,8247
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=mWTWI4wriGXC8UAnaeq_MIvWJOvf08-fPUqUgELptQ4,896
44
- opencos/tests/test_eda.py,sha256=eraWvyJJHrlq4CVoeWakYckRG8RRUYtecJRzlcXX45Q,38545
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=4zWBeFKXHSyb5WSnf6ZpVG2UwoKF0SC-00I1_VqgXZM,6016
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=mw4AfutGjKyCj7NLrHDy2j3p0XC2H7uuBf9RkVQJYoQ,9856
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=h9kkAi479cZzYfb4R9WBNY_JmR6BgVFj4s3VShnGpoA,7813
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=fELQZs4E__ZHW3Ubt_8vLb2jrw6VNP6xDhtwHutYvSk,39953
70
- opencos/tools/yosys.py,sha256=rYXKVn7A6Wx6o6R8vFy8nSR5TYlIxkDr5yAFXsX7FWg,9431
71
- opencos_eda-0.2.44.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
72
- opencos_eda-0.2.44.dist-info/licenses/LICENSE.spdx,sha256=8gn1610RMP6eFgT3Hm6q9VKXt0RvdTItL_oxMo72jII,189
73
- opencos_eda-0.2.44.dist-info/METADATA,sha256=BhZRe0n05IPoNS89ZHBwtd7_Tscn9P0tmNhCqZdB3aA,604
74
- opencos_eda-0.2.44.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- opencos_eda-0.2.44.dist-info/entry_points.txt,sha256=V8OE1lySAFcFQpDNJuVxVZteeSmDH-joLMhGvrxrvmg,164
76
- opencos_eda-0.2.44.dist-info/top_level.txt,sha256=J4JDP-LpRyJqPNeh9bSjx6yrLz2Mk0h6un6YLmtqql4,8
77
- opencos_eda-0.2.44.dist-info/RECORD,,
71
+ opencos/tools/vivado.py,sha256=_GVqKNIZt9CZeiXS5yZCWTFrhD3BKjcQfzhhxR1qLQM,40017
72
+ opencos/tools/yosys.py,sha256=FV43RcejyFir4B24WRShnzUoppJMK0sDDNkSlIX8Vew,25579
73
+ opencos_eda-0.2.46.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
74
+ opencos_eda-0.2.46.dist-info/licenses/LICENSE.spdx,sha256=8gn1610RMP6eFgT3Hm6q9VKXt0RvdTItL_oxMo72jII,189
75
+ opencos_eda-0.2.46.dist-info/METADATA,sha256=po0uwX8zxK4LmDW80yfBySMF1T2VwUifZPRgcsHB9f4,604
76
+ opencos_eda-0.2.46.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
77
+ opencos_eda-0.2.46.dist-info/entry_points.txt,sha256=V8OE1lySAFcFQpDNJuVxVZteeSmDH-joLMhGvrxrvmg,164
78
+ opencos_eda-0.2.46.dist-info/top_level.txt,sha256=J4JDP-LpRyJqPNeh9bSjx6yrLz2Mk0h6un6YLmtqql4,8
79
+ opencos_eda-0.2.46.dist-info/RECORD,,