opencos-eda 0.2.28__py3-none-any.whl → 0.2.32__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.
Files changed (35) hide show
  1. opencos/commands/export.py +2 -1
  2. opencos/commands/flist.py +49 -12
  3. opencos/commands/multi.py +101 -130
  4. opencos/commands/synth.py +0 -1
  5. opencos/commands/upload.py +7 -7
  6. opencos/commands/waves.py +50 -19
  7. opencos/deps_helpers.py +93 -3
  8. opencos/deps_schema.py +28 -18
  9. opencos/eda.py +6 -1
  10. opencos/eda_base.py +29 -10
  11. opencos/eda_config.py +1 -0
  12. opencos/eda_config_defaults.yml +4 -1
  13. opencos/eda_extract_deps_keys.py +27 -10
  14. opencos/files.py +6 -8
  15. opencos/names.py +1 -0
  16. opencos/oc_cli.py +143 -1
  17. opencos/peakrdl_cleanup.py +0 -1
  18. opencos/tests/helpers.py +38 -10
  19. opencos/tests/test_deps_helpers.py +46 -2
  20. opencos/tests/test_eda.py +65 -41
  21. opencos/tests/test_tools.py +17 -9
  22. opencos/tools/iverilog.py +0 -2
  23. opencos/tools/modelsim_ase.py +11 -5
  24. opencos/tools/questa.py +14 -19
  25. opencos/tools/verilator.py +0 -2
  26. opencos/tools/vivado.py +253 -112
  27. opencos/tools/yosys.py +1 -6
  28. opencos/util.py +4 -0
  29. {opencos_eda-0.2.28.dist-info → opencos_eda-0.2.32.dist-info}/METADATA +1 -1
  30. {opencos_eda-0.2.28.dist-info → opencos_eda-0.2.32.dist-info}/RECORD +35 -35
  31. {opencos_eda-0.2.28.dist-info → opencos_eda-0.2.32.dist-info}/WHEEL +1 -1
  32. {opencos_eda-0.2.28.dist-info → opencos_eda-0.2.32.dist-info}/entry_points.txt +0 -0
  33. {opencos_eda-0.2.28.dist-info → opencos_eda-0.2.32.dist-info}/licenses/LICENSE +0 -0
  34. {opencos_eda-0.2.28.dist-info → opencos_eda-0.2.32.dist-info}/licenses/LICENSE.spdx +0 -0
  35. {opencos_eda-0.2.28.dist-info → opencos_eda-0.2.32.dist-info}/top_level.txt +0 -0
opencos/tools/vivado.py CHANGED
@@ -10,6 +10,10 @@ import os
10
10
  import re
11
11
  import shlex
12
12
  import shutil
13
+ import sys
14
+
15
+ from datetime import datetime
16
+ from pathlib import Path
13
17
 
14
18
  from opencos import util, eda_base
15
19
  from opencos.eda_base import Tool
@@ -30,8 +34,14 @@ class ToolVivado(Tool):
30
34
 
31
35
  def __init__(self, config: dict):
32
36
  super().__init__(config=config) # calls self.get_versions()
33
- self.args['xilinx'] = False
34
- self.args['part'] = 'xcu200-fsgd2104-2-e'
37
+ self.args.update({
38
+ 'part': 'xcu200-fsgd2104-2-e',
39
+ 'add-glbl-v': False,
40
+ })
41
+ self.args_help.update({
42
+ 'part': 'Device used for commands: synth, build.',
43
+ 'add-glbl-v': '(for simulation) add glbl.v to filelist',
44
+ })
35
45
 
36
46
 
37
47
  def get_versions(self) -> str:
@@ -48,10 +58,10 @@ class ToolVivado(Tool):
48
58
 
49
59
  xilinx_vivado = os.environ.get('XILINX_VIVADO')
50
60
  if not xilinx_vivado or \
51
- os.path.abspath(os.path.join(xilinx_vivado, 'bin', 'vivado')) != \
52
- os.path.abspath(self.vivado_exe):
61
+ os.path.abspath(os.path.join(xilinx_vivado, 'bin')) != \
62
+ os.path.abspath(os.path.dirname(self.vivado_exe)):
53
63
  util.info("environment for XILINX_VIVADO is not set or doesn't match the vivado path:",
54
- f"{xilinx_vivado=}")
64
+ f"XILINX_VIVADO={xilinx_vivado} EXE PATH={self.vivado_exe}")
55
65
 
56
66
  version = None
57
67
  # Note this is commented out b/c it's a bit slow, up to 1.0 second to
@@ -91,12 +101,6 @@ class ToolVivado(Tool):
91
101
  self.defines['OC_TOOL_VIVADO'] = None
92
102
  def_year_release = f'OC_TOOL_VIVADO_{self.vivado_year:04d}_{self.vivado_release:d}'
93
103
  self.defines[def_year_release] = None
94
- if self.args['xilinx']:
95
- self.defines['OC_LIBRARY_ULTRASCALE_PLUS'] = None
96
- self.defines['OC_LIBRARY'] = "1"
97
- else:
98
- self.defines['OC_LIBRARY_BEHAVIORAL'] = None
99
- self.defines['OC_LIBRARY'] = "0"
100
104
 
101
105
  # Code can be conditional on Vivado versions and often keys of "X or older" ...
102
106
  versions = ['2021.1', '2021.2', '2022.1', '2022.2', '2023.1', '2023.2',
@@ -133,9 +137,18 @@ class CommandSimVivado(CommandSim, ToolVivado):
133
137
  CommandSim.__init__(self, config)
134
138
  ToolVivado.__init__(self, config=self.config)
135
139
  # add args specific to this simulator
136
- self.args['gui'] = False
137
- self.args['tcl-file'] = "sim.tcl"
138
- self.args['fpga'] = ""
140
+ self.args.update({
141
+ 'gui': False,
142
+ 'tcl-file': 'sim.tcl',
143
+ 'fpga': '',
144
+ 'add-glbl-v': False,
145
+ })
146
+ self.args_help.update({
147
+ 'gui': 'Run Vivado XSim in GUI mode',
148
+ 'tcl-file': 'name of TCL file to be created for XSim',
149
+ 'fpga': 'FPGA device name, can be used for various Xilinx IP or XCIs',
150
+ 'add-glbl-v': 'Use the glbl.v in xvlog for this version of Vivado',
151
+ })
139
152
 
140
153
  self.sim_libraries = self.tool_config.get('sim-libraries', [])
141
154
  self.xvlog_commands = []
@@ -198,10 +211,13 @@ class CommandSimVivado(CommandSim, ToolVivado):
198
211
  self.set_tool_defines()
199
212
  ret = [] # list of (list of ['xvlog', arg0, arg1, ..])
200
213
 
214
+ if self.args['add-glbl-v']:
215
+ self._add_glbl_v()
216
+
201
217
  # compile verilog
202
- if self.files_v or self.args['xilinx']:
218
+ if self.files_v:
203
219
  ret.append(
204
- self.get_xvlog_commands(files_list=self.files_v, typ='v', add_glbl_v=True)
220
+ self.get_xvlog_commands(files_list=self.files_v, typ='v')
205
221
  )
206
222
 
207
223
  # compile systemverilog
@@ -218,6 +234,8 @@ class CommandSimVivado(CommandSim, ToolVivado):
218
234
  os.path.join(self.vivado_base_path, 'xelab'),
219
235
  self.args['top']
220
236
  ]
237
+ if sys.platform == "win32":
238
+ command_list[0] += ".bat"
221
239
  command_list += self.tool_config.get('elab-args',
222
240
  '-s snapshot -timescale 1ns/1ps --stats').split()
223
241
  if self.tool_config.get('elab-waves-args', ''):
@@ -230,7 +248,7 @@ class CommandSimVivado(CommandSim, ToolVivado):
230
248
  command_list += ['-debug', 'wave']
231
249
  if util.args['verbose']:
232
250
  command_list += ['-v', '2']
233
- if self.args['xilinx']:
251
+ if self.args['sim-library'] or self.args['add-glbl-v']:
234
252
  self.sim_libraries += self.args['sim-library'] # Add any command line libraries
235
253
  for x in self.sim_libraries:
236
254
  command_list += ['-L', x]
@@ -265,11 +283,13 @@ class CommandSimVivado(CommandSim, ToolVivado):
265
283
 
266
284
  # execute snapshot
267
285
  command_list = [ os.path.join(self.vivado_base_path, 'xsim') ]
286
+ if sys.platform == "win32":
287
+ command_list[0] += ".bat"
268
288
  command_list += self.tool_config.get('simulate-args', 'snapshot --stats').split()
269
289
  if self.args['gui']:
270
290
  command_list += ['-gui']
271
291
  command_list += [
272
- '--tclbatch', tcl_name,
292
+ '--tclbatch', tcl_name.replace('\\','\\\\'), # needed for windows paths
273
293
  "--sv_seed", sv_seed
274
294
  ]
275
295
  command_list += xsim_plusargs_list
@@ -279,25 +299,21 @@ class CommandSimVivado(CommandSim, ToolVivado):
279
299
  def get_post_simulate_command_lists(self, **kwargs) -> list:
280
300
  return []
281
301
 
282
- def get_xvlog_commands(self, files_list: list,
283
- typ: str = 'sv', add_glbl_v: bool = False) -> list:
302
+ def get_xvlog_commands(self, files_list: list, typ: str = 'sv') -> list:
284
303
  '''Returns list. Vivado still treats .v files like Verilog-2001, so we split
285
304
 
286
305
  xvlog into .v and .sv sections'''
287
306
  command_list = []
307
+
288
308
  if files_list:
289
309
  command_list = [ os.path.join(self.vivado_base_path, 'xvlog') ]
310
+ if sys.platform == "win32":
311
+ command_list[0] += ".bat"
290
312
  if typ == 'sv':
291
313
  command_list.append('-sv')
292
314
  command_list += self.tool_config.get('compile-args', '').split()
293
315
  if util.args['verbose']:
294
316
  command_list += ['-v', '2']
295
- if (typ == 'v' or add_glbl_v) and self.args['xilinx']:
296
- # Get the right glbl.v for the vivado being used.
297
- glbl_v = self.vivado_base_path.replace('bin', 'data/verilog/src/glbl.v')
298
- if not os.path.exists(glbl_v):
299
- self.error(f"Could not find file {glbl_v=}")
300
- command_list.append(glbl_v)
301
317
  for value in self.incdirs:
302
318
  command_list.append('-i')
303
319
  command_list.append(value)
@@ -305,16 +321,27 @@ class CommandSimVivado(CommandSim, ToolVivado):
305
321
  command_list.append('-d')
306
322
  if value is None:
307
323
  command_list.append(key)
324
+ elif sys.platform == "win32":
325
+ command_list.append(f"\"{key}={value}\"") # only thing that seems to work
308
326
  elif "\'" in value:
309
327
  command_list.append(f"\"{key}={value}\"")
310
328
  else:
311
- command_list.append(f"\'{key}={value}\'")
329
+ command_list.append(f"{key}={value}")
312
330
  command_list += self.args['compile-args']
313
331
  command_list += files_list
314
332
  return command_list
315
333
 
316
334
 
317
-
335
+ def _add_glbl_v(self):
336
+ '''Adds glbl.v from Vivado's install path to self.files_v'''
337
+ glbl_v = self.vivado_base_path.replace('bin', 'data/verilog/src/glbl.v')
338
+ if any(x.endswith('glbl.v') for x in self.files_v):
339
+ util.warning(f'--add-glbl-v: Not adding {glbl_v=} b/c glbl.v already in',
340
+ f'{self.files_v=}')
341
+ elif not os.path.exists(glbl_v):
342
+ self.error(f"Could not find file {glbl_v=}")
343
+ else:
344
+ self.files_v.insert(0, glbl_v)
318
345
 
319
346
 
320
347
  class CommandElabVivado(CommandSimVivado):
@@ -559,6 +586,9 @@ class CommandProjVivado(CommandProj, ToolVivado):
559
586
  f"add_files -norecurse {f} -fileset [get_filesets {fileset}]"
560
587
  ]
561
588
 
589
+ tcl_lines += [
590
+ f"set_property top {self.args['top']} [get_filesets sim_1]"
591
+ ]
562
592
  with open( tcl_file, 'w', encoding='utf-8' ) as fo:
563
593
  fo.write('\n'.join(tcl_lines))
564
594
 
@@ -570,7 +600,7 @@ class CommandProjVivado(CommandProj, ToolVivado):
570
600
  if not util.args['verbose']:
571
601
  command_list.append('-notrace')
572
602
  self.exec(self.args['work-dir'], command_list)
573
- util.info(f"Synthesis done, results are in: {self.args['work-dir']}")
603
+ util.info(f"Project run done, results are in: {self.args['work-dir']}")
574
604
 
575
605
 
576
606
  class CommandBuildVivado(CommandBuild, ToolVivado):
@@ -600,12 +630,17 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
600
630
  '--tool', self.args['tool'],
601
631
  self.args['top-path'],
602
632
  '--force',
603
- '--xilinx',
604
633
  '--out', flist_file,
605
- '--no-emit-incdir',
606
- '--no-single-quote-define', # Needed to run in Command.exec( ... shell=False)
634
+ #'--no-emit-incdir',
635
+ #'--no-single-quote-define', # Needed to run in Command.exec( ... shell=False)
607
636
  '--no-quote-define',
637
+ #'--bracket-quote-define',
638
+ '--quote-define-value',
639
+ '--escape-define-value',
640
+ '--no-equal-define',
641
+ '--bracket-quote-path',
608
642
  # on --prefix- items, use shlex.quote(str) so spaces work with subprocess shell=False:
643
+ '--prefix-incdir', shlex.quote("oc_set_project_incdir "),
609
644
  '--prefix-define', shlex.quote("oc_set_project_define "),
610
645
  '--prefix-sv', shlex.quote("add_files -norecurse "),
611
646
  '--prefix-v', shlex.quote("add_files -norecurse "),
@@ -674,96 +709,202 @@ class CommandUploadVivado(CommandUpload, ToolVivado):
674
709
  CommandUpload.__init__(self, config)
675
710
  ToolVivado.__init__(self, config=self.config)
676
711
  # add args specific to this simulator
677
- self.args['gui'] = False
678
- self.args['file'] = False
679
- self.args['usb'] = True
680
- self.args['host'] = "localhost"
681
- self.args['port'] = 3121
682
- self.args['target'] = 0
683
- self.args['tcl-file'] = "upload.tcl"
712
+ self.args.update({
713
+ 'gui': False,
714
+ 'bitfile': "",
715
+ 'list-usbs': False,
716
+ 'list-devices': False,
717
+ 'list-bitfiles': False,
718
+ 'usb': -1,
719
+ 'device': -1,
720
+ 'host': "localhost",
721
+ 'port': 3121,
722
+ 'tcl-file': "upload.tcl",
723
+ 'test-mode': False,
724
+ })
725
+ # TODO(drew): Add self.args_help.update({...})
726
+
727
+ # TODO(drew): This method needs to be refactored (with tests somehow) to clean
728
+ # up pylint waivers
729
+ def do_it(self): # pylint: disable=too-many-locals,too-many-branches,too-many-statements
730
+ # add defines for this job
731
+ self.set_tool_defines()
732
+ self.write_eda_config_and_args()
684
733
 
685
- def do_it(self):
686
- if not self.args['file']:
687
- util.info("Searching for bitfiles...")
688
- found_file = False
689
- all_files = []
734
+ bitfile = None
735
+ targets = []
736
+ if self.args['bitfile']:
737
+ if os.path.isfile(self.args['bitfile']):
738
+ bitfile = self.args['bitfile']
739
+ else:
740
+ # Not a file, treat as search pattern
741
+ targets = [self.args['bitfile']]
742
+
743
+ # TODO(drew): It might be nice to use positional args (supported by
744
+ # eda_base.Command) here, and in multi.py, so we don't accidentally
745
+ # grab errant --arg style strings as potential filenames or target patterns
746
+ for f in self.unparsed_args:
747
+ # self.unparsed_args are leftovers from Command.process_tokens(..)
748
+ if os.path.isfile(f):
749
+ if bitfile is None:
750
+ bitfile = f
751
+ else:
752
+ util.error("Too many bitfiles provided")
753
+ if not self.args['test-mode']:
754
+ sys.exit(0)
755
+ else:
756
+ # Not a file, treat as search pattern
757
+ targets.append(f)
758
+
759
+ # Auto-discover bitfile logic (for when we have no bitfile, and we
760
+ # weren't called just to listdevice/listusb)
761
+ if self.args['list-bitfiles'] or \
762
+ (not bitfile and not self.args['list-devices'] and not self.args['list-usbs']):
763
+ bitfiles: list[Path] = []
764
+
765
+ util.debug(f"Looking for bitfiles in {os.path.abspath('.')=}")
690
766
  for root, _, files in os.walk("."):
691
- for file in files:
692
- if file.endswith(".bit"):
693
- found_file = os.path.abspath(os.path.join(root,file))
694
- util.info(f"Found bitfile: {found_file}")
695
- all_files.append(found_file)
696
- self.args['file'] = found_file
767
+ for f in files:
768
+ if f.endswith(".bit"):
769
+ fullpath = os.path.abspath(Path(root) / f)
770
+ if fullpath not in bitfiles:
771
+ bitfiles.append(fullpath)
772
+
773
+ matched: list[Path] = []
774
+ for cand in bitfiles:
775
+ util.debug(f"Looking for {cand=} in {targets=}")
776
+ passing = all(re.search(t, str(cand)) for t in targets)
777
+ if passing:
778
+ matched.append(cand)
779
+ mod_time_string = datetime.fromtimestamp(
780
+ os.path.getmtime(cand)).strftime('%Y-%m-%d %H:%M:%S')
781
+ util.info(f"Found matching bitfile: {mod_time_string} : {cand}")
782
+
783
+ if len(matched) > 1:
784
+ if self.args['list-bitfiles']:
785
+ util.info("Too many matches to continue without adding search terms. Done.")
786
+ if not self.args['test-mode']:
787
+ sys.exit(0)
788
+ else:
789
+ util.error("Too many matches, please add search terms...")
697
790
 
698
- if len(all_files) > 1:
699
- all_files.sort(key=os.path.getmtime)
700
- self.args['file'] = all_files[-1]
701
- util.info(f"Choosing: {self.args['file']} (newest)")
791
+ if not matched and bitfile is None:
792
+ if self.args['list-bitfiles']:
793
+ util.info("No matching bitfiles found, done.")
794
+ if not self.args['test-mode']:
795
+ sys.exit(0)
796
+ else:
797
+ util.error("Failed to find a matching bitfile")
798
+
799
+ if matched and bitfile is None:
800
+ bitfile = matched[0]
801
+
802
+ # ── Generate TCL script ───────────────────────────────────────────────────
803
+ script_file = Path(self.args['tcl-file'])
804
+ log_file = Path("eda_upload.log")
805
+
806
+ try:
807
+ with script_file.open("w", encoding="utf-8") as fout:
808
+ w = fout.write # local alias (brevity)
809
+
810
+ w('open_hw_manager\n')
811
+ w(f'connect_hw_server -url {self.args["host"]}:{self.args["port"]}\n')
812
+ w('refresh_hw_server -force_poll\n')
813
+
814
+ w('set hw_targets [get_hw_targets -quiet */xilinx_tcf/Xilinx/*]\n')
815
+ w('set num_targets [llength $hw_targets]\n')
816
+ if self.args['list-usbs']:
817
+ w('puts "\\[INFO\\] OC_LOAD_BITFILE TCL $num_targets USB targets found"\n')
818
+ w('for {set u 0} {$u < $num_targets} {incr u} {\n')
819
+ w(' puts "\\[INFO\\] OC_LOAD_BITFILE TCL: USB $u : [lindex $hw_targets $u]"\n')
820
+ w('}\n')
821
+ w('if { $num_targets > 1} {\n')
822
+ w(' set maxusb [expr $num_targets - 1]\n')
823
+ w(' puts "\\[INFO\\] OC_LOAD_BITFILE TCL: With >1 target you need to specify'
824
+ '--usb <n> where <n> is 0-$maxusb"\n')
825
+ w('}\n')
826
+ w('if { $num_targets == 0 } {\n')
827
+ w(' puts "\\[ERROR\\] OC_LOAD_BITFILE TCL: No HW_targets found!"\n')
828
+ w(' exit\n}\n')
829
+
830
+ if self.args['usb'] == -1:
831
+ w('if { $num_targets == 1 } {\n')
832
+ w(' puts "\\[INFO\\] OC_LOAD_BITFILE TCL: Defaulting to USB #0, since there is'
833
+ 'only one device"\n')
834
+ w(' set usb 0\n} else {\n')
835
+ if not self.args['list-usbs']:
836
+ w(' set maxusb [expr $num_targets - 1]\n')
837
+ w(' puts "\\[ERROR\\] OC_LOAD_BITFILE TCL: Need --usb <n> argument, <n>'
838
+ 'being 0-$maxusb, use --list-usbs if needed"\n')
839
+ w(' exit\n}\n')
840
+ else:
841
+ w(f'set usb {self.args["usb"]}\n')
842
+
843
+ w('if { $num_targets <= $usb } {\n')
844
+ w(' puts "\\[ERROR\\] OC_LOAD_BITFILE TCL: hw_target #$usb doesn\'t exist!!"\n')
845
+ w(' exit\n}\n')
846
+ w('set hw_target [lindex $hw_targets $usb]\n')
847
+ w('current_hw_target $hw_target\n')
848
+ w('open_hw_target\n')
849
+ w('refresh_hw_target\n')
850
+
851
+ w('set hw_devices [get_hw_devices -quiet]\n')
852
+ w('set num_devices [llength $hw_devices]\n')
853
+ if self.args['list-devices']:
854
+ w('puts "\\[INFO\\] OC_LOAD_BITFILE TCL $num_devices devices found"\n')
855
+ w('for {set d 0} {$d < $num_devices} {incr d} {\n')
856
+ w(' puts "\\[INFO\\] OC_LOAD_BITFILE TCL: Device $d :'
857
+ '[lindex $hw_devices $d]"\n')
858
+ w('}\n')
859
+
860
+ if self.args['device'] == -1:
861
+ w('if { $num_devices > 1 } {\n')
862
+ w(' if { [lindex $hw_devices 0] eq "arm_dap_0" } {\n')
863
+ w(' set hw_device [lindex $hw_devices 1]\n } else {\n')
864
+ w(' set hw_device [lindex $hw_devices 0]\n }\n')
865
+ w('}\n')
866
+ else:
867
+ w(f'set hw_device [lindex $hw_devices {self.args["device"] }]\n')
702
868
 
703
- if not self.args['file']:
704
- self.error("Couldn't find a bitfile to upload, and/or --file not set.")
705
-
706
- if self.args['usb']:
707
- util.info(f"Uploading bitfile: {self.args['file']}")
708
- util.info(f"Uploading via {self.args['host']}:{self.args['port']}",
709
- f"USB target #{self.args['target']}")
710
- self.upload_usb_jtag(
711
- self.args['host'], self.args['port'], self.args['target'], self.args['file']
712
- )
869
+ w('puts "HW_DEVICE DID : [get_property DID $hw_device]"\n')
870
+ w('puts "HW_DEVICE PART : [get_property PART $hw_device]"\n')
871
+ w('current_hw_device $hw_device\n')
872
+ w('refresh_hw_device -update_hw_probes false -quiet $hw_device\n')
873
+
874
+ if bitfile is not None:
875
+ w('set_property PROGRAM.FILE {' + bitfile + '} $hw_device\n')
876
+ w('program_hw_devices [current_hw_device]\n')
877
+
878
+ w('close_hw_target\n')
879
+
880
+ except OSError as exc:
881
+ util.error(f"Cannot create {script_file}: {exc}")
882
+
883
+ if bitfile is None:
884
+ util.info("No bitfile provided or found")
713
885
  else:
714
- self.error("Only know how to upload via USB for now, args --usb not set.")
715
- self.write_eda_config_and_args()
886
+ if os.path.isfile(bitfile):
887
+ util.info(f"Using bitfile {bitfile}")
888
+ else:
889
+ util.warning(f"Using bitfile {bitfile}, which doesn't exist (or is not a file)")
716
890
 
717
- def upload_usb_jtag(self, host, port, target, bit_file):
718
- '''Returns None, creats and runs a tcl to run in Vivado 'open_hw'. '''
719
- # create TCL
720
- tcl_file = os.path.abspath(os.path.join(self.args['work-dir'], self.args['tcl-file']))
721
- ltx_file = os.path.splitext(bit_file)[0] + ".ltx"
722
- if not os.path.exists(ltx_file):
723
- ltx_file = False
891
+ if self.args['test-mode']:
892
+ util.info(f"test-mode set, upload skipped, {script_file=}")
893
+ return
724
894
 
725
- tcl_lines = [
726
- "open_hw",
727
- f"connect_hw_server -url {host}:{port}",
728
- "refresh_hw_server -force_poll",
729
- "set hw_targets [get_hw_targets */xilinx_tcf/Xilinx/*]",
730
- f"if {{ [llength $hw_targets] <= {target} }} {{",
731
- f" puts \"ERROR: There is no target number {target}\"",
732
- "}}",
733
- f"current_hw_target [lindex $hw_targets {target}]",
734
- "open_hw_target",
735
- "refresh_hw_target",
736
- "current_hw_device [lindex [get_hw_devices] 0]",
737
- "refresh_hw_device [current_hw_device]",
738
- f"set_property PROGRAM.FILE {bit_file} [current_hw_device]",
739
- ]
740
- if ltx_file:
741
- tcl_lines += [
742
- f"set_property PROBES.FILE {ltx_file} [current_hw_device]",
743
- ]
744
- tcl_lines += [
745
- "program_hw_devices [current_hw_device]",
895
+ # ── Execute Vivado ───────────────────────────────────────────────────────
896
+ command_list = [
897
+ self.vivado_exe, '-mode', 'batch', '-source', str(script_file), '-log', str(log_file)
746
898
  ]
747
- if self.args['gui']:
748
- tcl_lines += [
749
- "refresh_hw_device [current_hw_device]",
750
- "display_hw_ila_data [ get_hw_ila_data hw_ila_data_1 -of_objects [get_hw_ilas] ]",
751
- ]
752
- else:
753
- tcl_lines += [
754
- "close_hw_target",
755
- "exit",
756
- ]
899
+ if not util.args['verbose']:
900
+ command_list.append('-notrace')
901
+ self.exec(Path(util.getcwd()), command_list)
902
+
903
+ util.info("Upload done")
904
+
905
+
757
906
 
758
- with open( tcl_file, 'w', encoding='utf-8' ) as fo:
759
- fo.write('\n'.join(tcl_lines))
760
907
 
761
- # execute Vivado
762
- command_list = [ self.vivado_exe, '-source', tcl_file, '-log', "fpga.upload.log" ]
763
- if not self.args['gui']:
764
- command_list.append('-mode')
765
- command_list.append('batch')
766
- self.exec(self.args['work-dir'], command_list)
767
908
 
768
909
  class CommandOpenVivado(CommandOpen, ToolVivado):
769
910
  '''CommandOpenVivado command handler class used by: eda open --tool vivado'''
opencos/tools/yosys.py CHANGED
@@ -66,12 +66,7 @@ class ToolYosys(Tool):
66
66
  self.defines.update({
67
67
  'OC_TOOL_YOSYS': None
68
68
  })
69
- if self.args['xilinx']:
70
- self.defines.update({
71
- 'OC_LIBRARY_ULTRASCALE_PLUS': None,
72
- 'OC_LIBRARY': "1"
73
- })
74
- else:
69
+ if 'OC_LIBRARY' not in self.defines:
75
70
  self.defines.update({
76
71
  'OC_LIBRARY_BEHAVIORAL': None,
77
72
  'OC_LIBRARY': "0"
opencos/util.py CHANGED
@@ -451,6 +451,8 @@ def get_oc_root(error_on_fail:bool=False):
451
451
  print_didnt_find_it(f'Unable to get a OC_ROOT directory using git rev-parse')
452
452
  else:
453
453
  _oc_root = cp.stdout.strip()
454
+ if sys.platform == 'win32':
455
+ _oc_root = _oc_root.replace('/', '\\') # git gives us /, but we need \
454
456
 
455
457
  # there is no sense running through this code more than once
456
458
  _oc_root_set = True
@@ -580,6 +582,8 @@ def write_shell_command_file(dirpath : str, filename : str, command_lists : list
580
582
  assert type(command_lists) is list, f'{command_lists=}'
581
583
  fullpath = os.path.join(dirpath, filename)
582
584
  with open(fullpath, 'w') as f:
585
+ if not bash_path:
586
+ bash_path = "/bin/bash" # we may not get far, but we'll try
583
587
  f.write('#!' + bash_path + '\n\n')
584
588
  for obj in command_lists:
585
589
  assert isinstance(obj, list), f'{obj=} (obj must be list/ShellCommandList) {command_lists=}'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.2.28
3
+ Version: 0.2.32
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