opencos-eda 0.2.41__py3-none-any.whl → 0.2.43__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/eda_base.py CHANGED
@@ -667,13 +667,15 @@ class CommandDesign(Command):
667
667
  self.args.update({
668
668
  'seed': seed.get_seed(style="urandom"),
669
669
  'top': '',
670
- 'all-sv': False,
670
+ 'all-sv': True,
671
671
  'unprocessed-plusargs': [],
672
672
  })
673
673
  self.args_help.update({
674
674
  'seed': 'design seed, default is 31-bit non-zero urandom',
675
675
  'top': 'TOP level verilog/SV module or VHDL entity for this target',
676
- 'all-sv': 'Maintain .sv and .v in single file list. (if False: .sv flist separate from .v flist)',
676
+ 'all-sv': ('Maintain .sv and .v in single file list.'
677
+ ' False: .sv flist separate from .v flist and separate compile(s)'
678
+ ' True: .sv and .v files compiled together if possible'),
677
679
  'unprocessed-plusargs': 'Args that began with +, but were not +define+ or +incdir+, +<name>, ' \
678
680
  + ' or +<name>=<value>. These become tool dependent, for example "sim" commands will treat as sim-plusargs',
679
681
  })
@@ -694,6 +696,7 @@ class CommandDesign(Command):
694
696
 
695
697
  self.cached_deps = {} # key = abspath of DEPS markup file, has sub-dicts for 'data' and 'line_numbers'.
696
698
  self.targets_dict = {} # key = targets that we've already processed in DEPS files
699
+ self.last_added_source_file_inferred_top = ''
697
700
 
698
701
  def run_dep_commands(self):
699
702
  # Run any shell@ commands from DEPS files
@@ -1034,6 +1037,11 @@ class CommandDesign(Command):
1034
1037
  file_ext = known_file_ext_dict.get(forced_extension, [''])[0]
1035
1038
  util.debug(f"{forced_extension=} for {filename=} as type '{file_ext}'")
1036
1039
 
1040
+
1041
+ if not add_to_non_sources and \
1042
+ file_ext in known_file_ext_dict.get('inferred_top', []):
1043
+ self.last_added_source_file_inferred_top = file_abspath
1044
+
1037
1045
  if add_to_non_sources:
1038
1046
  self.files_non_source.append(file_abspath)
1039
1047
  util.debug("Added non-source file file %s as %s" % (filename, file_abspath))
@@ -1112,8 +1120,8 @@ class CommandDesign(Command):
1112
1120
 
1113
1121
  # by this point hopefully this is a target ... is it a simple filename?
1114
1122
  remove_list = []
1115
- last_potential_top = None # used for 'top' if top not specified.
1116
- last_potential_top_path = None
1123
+ last_potential_top_file = ('', '') # (top, fpath)
1124
+ last_potential_top_target = ('', '') # (top, path/to/full-target-name)
1117
1125
  last_potential_top_isfile = False
1118
1126
  caller_info = ''
1119
1127
  for token in unparsed:
@@ -1129,21 +1137,13 @@ class CommandDesign(Command):
1129
1137
  else:
1130
1138
  self.add_file(filename=fpath, caller_info=caller_info,
1131
1139
  forced_extension=forced_extension)
1132
-
1133
- known_file_ext_dict = self.config.get('file_extensions', {})
1134
- if forced_extension:
1135
- # If forced_extension='systemverilog', then use the first known extension for
1136
- # it ('.sv', from eda_config_defaults.yml):
1137
- file_ext = known_file_ext_dict.get(forced_extension, [''])[0]
1138
-
1139
- if not self.args['top'] and \
1140
- file_ext and \
1141
- file_ext in known_file_ext_dict.get('inferred_top', []):
1142
- # if we haven't yet been given a top, or inferred one, we take the last one we get
1143
- # from a raw list of RTL file names (from args or command line tokens)
1144
- last_potential_top_path = file_abspath
1145
- last_potential_top = self.get_top_name(file_abspath)
1146
- last_potential_top_isfile = True
1140
+ if not self.args['top']:
1141
+ known_file_ext_dict = self.config.get('file_extensions', {})
1142
+ if forced_extension:
1143
+ file_ext = known_file_ext_dict.get(forced_extension, [''])[0]
1144
+ if file_ext in known_file_ext_dict.get('inferred_top', []):
1145
+ # last cmd line arg was a filename that could have inferred top.
1146
+ last_potential_top_isfile = True
1147
1147
 
1148
1148
  remove_list.append(token)
1149
1149
  continue # done with token, consume it, we added the file.
@@ -1156,12 +1156,9 @@ class CommandDesign(Command):
1156
1156
 
1157
1157
  util.debug(f'Calling self.resolve_target on {target_name=}')
1158
1158
  if self.resolve_target(target_name, caller_info=caller_info):
1159
- if self.args['top'] == '':
1160
- # if we haven't yet been given a top, or inferred one, we take the last named target
1161
- # from args or command line tokens
1162
- # from a target name
1163
- last_potential_top = self.get_top_name(target_name)
1164
- last_potential_top_path = target_name
1159
+ if not self.args['top']:
1160
+ # last cmd line arg was a target that we'll likely use for inferred top.
1161
+ last_potential_top_target = (self.get_top_name(target_name), target_name)
1165
1162
  last_potential_top_isfile = False
1166
1163
 
1167
1164
  remove_list.append(token)
@@ -1174,16 +1171,35 @@ class CommandDesign(Command):
1174
1171
  if process_all and len(unparsed) > 0:
1175
1172
  self.error(f"Didn't understand command remaining tokens {unparsed=} in CommandDesign")
1176
1173
 
1177
- # handle a missing self.args['top'] with last filepath.
1178
- if self.args.get('top', '') == '' and last_potential_top is not None:
1179
- self.args['top'] = last_potential_top
1180
- self.args['top-path'] = last_potential_top_path
1181
- util.info(f"Inferred --top {self.args['top']} {self.args['top-path']}")
1182
- if last_potential_top_isfile:
1183
- # top wasn't set, we're using the final command-line 'arg' filename (not from DEPS.yml)
1184
- # need to override self.target if that was set. Otherwise it won't save to the correct
1185
- # work-dir:
1186
- self.target = last_potential_top
1174
+ # handle a missing self.args['top'] with last filepath or last target:
1175
+ if not self.args.get('top', ''):
1176
+ if not last_potential_top_isfile and last_potential_top_target[0]:
1177
+ # If we have a target name from DEPS, prefer to use that.
1178
+ self.args['top'], self.args['top-path'] = last_potential_top_target
1179
+ util.info("--top not specified, inferred from target:",
1180
+ f"{self.args['top']} ({self.args['top-path']})")
1181
+
1182
+ else:
1183
+ best_top_fname = self.last_added_source_file_inferred_top
1184
+ if best_top_fname:
1185
+ last_potential_top_file = (self.get_top_name(best_top_fname), best_top_fname)
1186
+
1187
+ if not self.args['top'] and last_potential_top_file[0]:
1188
+ # If we don't have a target name, and no top name yet, then go looking for the
1189
+ # module name in the final source file added.
1190
+ self.args['top-path'] = last_potential_top_file[1] # from tuple: (top, fpath)
1191
+ self.args['top'] = util.get_inferred_top_module_name(
1192
+ module_guess=last_potential_top_file[0],
1193
+ module_fpath=last_potential_top_file[1]
1194
+ )
1195
+ if self.args['top']:
1196
+ util.info("--top not specified, inferred from final source file:",
1197
+ f"{self.args['top']} ({self.args['top-path']})")
1198
+ # If top wasn't set, and we're using the final command-line 'arg' filename
1199
+ # (not from DEPS.yml) we need to override self.target if that was set. Otherwise
1200
+ # it won't save to the correct work-dir:
1201
+ self.target = self.args['top']
1202
+
1187
1203
  if self.error_on_missing_top and not self.args.get('top', ''):
1188
1204
  self.error(f"Did not get a --top or DEPS top, required to run command",
1189
1205
  f"'{self.command_name}' for tool={self.args.get('tool', None)}")
opencos/tests/helpers.py CHANGED
@@ -19,7 +19,7 @@ def can_run_eda_command(*commands, config: dict) -> bool:
19
19
  if not handler:
20
20
  return False
21
21
  if handler and getattr(handler, 'CHECK_REQUIRES', []):
22
- if not all(isinstance(handler, x) for x in getattr(handler, 'CHECK_REQUIRES', [])):
22
+ if not all(issubclass(handler, x) for x in getattr(handler, 'CHECK_REQUIRES', [])):
23
23
  return False
24
24
  runnable.append(True)
25
25
  return runnable and all(runnable)
@@ -166,6 +166,10 @@ class VerilatorSim(CommandSim, ToolVerilator):
166
166
  # don't run this if we're stopping before/after compile/elab
167
167
  return
168
168
 
169
+ if not os.path.isfile(os.path.join(self.args['work-dir'], 'obj_dir', 'sim.exe')):
170
+ self.error('Verilated executable obj_dir/sim.exe does not exist')
171
+ return
172
+
169
173
  # Note that this is not returning a pass/fail bash return code,
170
174
  # so we will likely have to log-scrape to deterimine pass/fail.
171
175
  # Also, if we ran in cc-mode, we will not get the "R e p o r t: Verilator"
opencos/tools/vivado.py CHANGED
@@ -142,6 +142,7 @@ class CommandSimVivado(CommandSim, ToolVivado):
142
142
  'tcl-file': 'sim.tcl',
143
143
  'fpga': '',
144
144
  'add-glbl-v': False,
145
+ 'all-sv': False,
145
146
  })
146
147
  self.args_help.update({
147
148
  'gui': 'Run Vivado XSim in GUI mode',
@@ -362,6 +363,7 @@ class CommandSynthVivado(CommandSynth, ToolVivado):
362
363
  self.args['tcl-file'] = "synth.tcl"
363
364
  self.args['xdc'] = ""
364
365
  self.args['fpga'] = ""
366
+ self.args['all-sv'] = False
365
367
 
366
368
  def do_it(self) -> None:
367
369
  CommandSynth.do_it(self)
@@ -533,6 +535,7 @@ class CommandProjVivado(CommandProj, ToolVivado):
533
535
  self.args['tcl-file'] = "proj.tcl"
534
536
  self.args['xdc'] = ""
535
537
  self.args['board'] = ""
538
+ self.args['all-sv'] = False
536
539
 
537
540
  def do_it(self):
538
541
  # add defines for this job
@@ -614,6 +617,7 @@ class CommandBuildVivado(CommandBuild, ToolVivado):
614
617
  self.args['fpga'] = ""
615
618
  self.args['proj'] = False
616
619
  self.args['reset'] = False
620
+ self.args['all-sv'] = False
617
621
 
618
622
  def do_it(self):
619
623
  # add defines for this job
@@ -700,6 +704,7 @@ class CommandFListVivado(CommandFList, ToolVivado):
700
704
  def __init__(self, config: dict):
701
705
  CommandFList.__init__(self, config=config)
702
706
  ToolVivado.__init__(self, config=self.config)
707
+ self.args['all-sv'] = False
703
708
 
704
709
 
705
710
  class CommandUploadVivado(CommandUpload, ToolVivado):
@@ -720,6 +725,7 @@ class CommandUploadVivado(CommandUpload, ToolVivado):
720
725
  'host': "localhost",
721
726
  'port': 3121,
722
727
  'tcl-file': "upload.tcl",
728
+ 'all-sv': False,
723
729
  })
724
730
  # TODO(drew): Add self.args_help.update({...})
725
731
 
@@ -913,6 +919,7 @@ class CommandOpenVivado(CommandOpen, ToolVivado):
913
919
  # add args specific to this simulator
914
920
  self.args['gui'] = True
915
921
  self.args['file'] = False
922
+ self.args['all-sv'] = False
916
923
 
917
924
  def do_it(self):
918
925
  if not self.args['file']:
opencos/util.py CHANGED
@@ -635,6 +635,38 @@ def write_eda_config_and_args(dirpath : str, filename='eda_output_config.yml', c
635
635
  yaml_safe_writer(data=data, filepath=fullpath)
636
636
 
637
637
 
638
+ def get_inferred_top_module_name(module_guess: str, module_fpath: str) -> str:
639
+ '''Returns the best guess as the 'top' module name name, given a fpath where
640
+
641
+ module_fpath = /some/path/to/module_guess.[v|sv]
642
+
643
+ Use the module_guess if it exists in the file as: module <module_guess>
644
+ Otherwise use the last observed: module <best_guess>
645
+ Otherwise use blank str
646
+ '''
647
+
648
+ best_guess = ''
649
+ if not os.path.isfile(module_fpath):
650
+ return ''
651
+ with open(module_fpath, encoding='utf-8') as f:
652
+ for line in f.readlines():
653
+ line = line.strip()
654
+ if line.startswith('module '):
655
+ parts = line.split()
656
+ module_name = parts[1]
657
+ rstrip_nonword_pattern = r'\W+$'
658
+ module_name = re.sub(rstrip_nonword_pattern, '', module_name)
659
+ if bool(re.fullmatch(r'^\w+$', module_name)):
660
+ if module_name == module_guess:
661
+ return module_guess
662
+ elif module_name:
663
+ best_guess = module_name
664
+ if best_guess:
665
+ return best_guess
666
+ else:
667
+ return ''
668
+
669
+
638
670
  def subprocess_run(work_dir, command_list, fake:bool=False, shell=False) -> int:
639
671
  ''' Run command_list in the foreground, with preference to use bash if shell=True.'''
640
672
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.2.41
3
+ Version: 0.2.43
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
@@ -4,7 +4,7 @@ opencos/_waves_pkg.sv,sha256=1lbhQOVGc3t_R8czYjP40hssP0I3FlZOpHTkI7yKFbI,1251
4
4
  opencos/deps_helpers.py,sha256=Pgo3dO_QBHzGB0lE2B0uf2vWWDy3dSDN0pvW-eA6ocs,56939
5
5
  opencos/deps_schema.py,sha256=MhytzXwp071F14RwxqHt78ak8Qruoe4FeK5XSzkO2f0,14658
6
6
  opencos/eda.py,sha256=WAmHCywd3mfgEH4oZgiCDDprXbH-EIjduYpBXlwzhE8,19133
7
- opencos/eda_base.py,sha256=I5BnL50SfJniU-I4_7kKvhBqNpev-MZcX9SMhSsDPrU,82373
7
+ opencos/eda_base.py,sha256=jtBKhlOMuE9G6_BgTpy-6SfkwnmMIoRKkmr1nLMnFHA,83276
8
8
  opencos/eda_config.py,sha256=fFKe-IdZb3RpOYjefCy_G1NrVzPcuHyXtAQp917GEuQ,8850
9
9
  opencos/eda_config_defaults.yml,sha256=U3QttzoxFH0hjElzaejaNa7XStgdX8EYULeRvZGPVUM,11087
10
10
  opencos/eda_config_max_verilator_waivers.yml,sha256=lTAU4IOEbUWVlPzuer1YYhIyxpPINeA4EJqcRIT-Ymk,840
@@ -20,7 +20,7 @@ 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=3rADW0tUzq69wdHsa2GB060N1jCAK2Dk0NLx6N6BMcc,27861
23
+ opencos/util.py,sha256=2Lm6rTZDWxkMBM22HYyI0a4ZC24XIXmdNuUUA_hmkcE,29010
24
24
  opencos/commands/__init__.py,sha256=d-8heMkBjjm6_yeduZgUv34lPfHVpj9MWP1ifpdjJws,916
25
25
  opencos/commands/build.py,sha256=jI5ul53qfwn6X-yfSdSQIcLBhGtzZUk7r_wKBBmKJI0,1425
26
26
  opencos/commands/elab.py,sha256=m6Gk03wSzX8UkcmReooK7turF7LpqO0IcdOZwJ8XiyI,1596
@@ -37,7 +37,7 @@ opencos/commands/upload.py,sha256=nlb4nlxrDCQPcabEmH3nP19g4PFILDqFDab4LwJ95Z4,79
37
37
  opencos/commands/waves.py,sha256=SRfjfsqhuszXHylQrgqYiUT3a5CQs9doxJQzuV4Ae0w,7055
38
38
  opencos/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  opencos/tests/custom_config.yml,sha256=TRoVM9ZFKPOA_8JmlpzaMhnGO1txmaD14N_8P1oqzew,257
40
- opencos/tests/helpers.py,sha256=zzQQP8ZeNUwrvJRQVlpTnvz9yxFG0Jfuss50ZPjxa-c,8240
40
+ opencos/tests/helpers.py,sha256=4HprNNHHgQEcFgtOC_NH8OZGb4Shn-ZNOKEjAtCZWWs,8240
41
41
  opencos/tests/test_build.py,sha256=FQAxOpLVQShAHD_L5rqJctPeSAoqoOCNFI0RXflLuY0,387
42
42
  opencos/tests/test_deps_helpers.py,sha256=_nJSgLN6WVlMKqu6sCr29gjQyN3Jj-dVk8Ac64ygpJs,5928
43
43
  opencos/tests/test_deps_schema.py,sha256=mWTWI4wriGXC8UAnaeq_MIvWJOvf08-fPUqUgELptQ4,896
@@ -65,13 +65,13 @@ opencos/tools/slang.py,sha256=74EDAAnN7mrrYxgxaPDaoRJZK7Se9B_HsW8Ioi2Nw44,7425
65
65
  opencos/tools/slang_yosys.py,sha256=mw4AfutGjKyCj7NLrHDy2j3p0XC2H7uuBf9RkVQJYoQ,9856
66
66
  opencos/tools/surelog.py,sha256=JOMs8SqnzJ_ZL5mEdyyn3Z1r1Kc8hfbV3Pnen1YzxWA,4980
67
67
  opencos/tools/tabbycad_yosys.py,sha256=h9kkAi479cZzYfb4R9WBNY_JmR6BgVFj4s3VShnGpoA,7813
68
- opencos/tools/verilator.py,sha256=lxR7BSmeTc6YcL0UuXzIfJk7umVm8RfbU8rtYtbKUBg,18192
69
- opencos/tools/vivado.py,sha256=1dbQ-5oUUaUNIeMp07HArWG15spG81OuCwJ88qRNXU0,39102
68
+ opencos/tools/verilator.py,sha256=DszHtJdLJg-UogRaB_jhel-qXn4KEiiAgj91uqB52R8,18380
69
+ opencos/tools/vivado.py,sha256=ZRr2b7dCbDL4YQReHdkCnF06XMcsEduRowtm_UI8WOM,39344
70
70
  opencos/tools/yosys.py,sha256=aZnRFbsODYRe4BHbfxl6vfWeEP7WJYJk50gCZcn8Fu0,8902
71
- opencos_eda-0.2.41.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
72
- opencos_eda-0.2.41.dist-info/licenses/LICENSE.spdx,sha256=8gn1610RMP6eFgT3Hm6q9VKXt0RvdTItL_oxMo72jII,189
73
- opencos_eda-0.2.41.dist-info/METADATA,sha256=RqZ9aufOroQoOauG7xsz2gGxPll_wY7svb6i0YsLGqw,604
74
- opencos_eda-0.2.41.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- opencos_eda-0.2.41.dist-info/entry_points.txt,sha256=V8OE1lySAFcFQpDNJuVxVZteeSmDH-joLMhGvrxrvmg,164
76
- opencos_eda-0.2.41.dist-info/top_level.txt,sha256=J4JDP-LpRyJqPNeh9bSjx6yrLz2Mk0h6un6YLmtqql4,8
77
- opencos_eda-0.2.41.dist-info/RECORD,,
71
+ opencos_eda-0.2.43.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
72
+ opencos_eda-0.2.43.dist-info/licenses/LICENSE.spdx,sha256=8gn1610RMP6eFgT3Hm6q9VKXt0RvdTItL_oxMo72jII,189
73
+ opencos_eda-0.2.43.dist-info/METADATA,sha256=jc6AEx0fn-xauyw9Y-JQ0FckIisJl68OPQ4Td0KP2eE,604
74
+ opencos_eda-0.2.43.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
+ opencos_eda-0.2.43.dist-info/entry_points.txt,sha256=V8OE1lySAFcFQpDNJuVxVZteeSmDH-joLMhGvrxrvmg,164
76
+ opencos_eda-0.2.43.dist-info/top_level.txt,sha256=J4JDP-LpRyJqPNeh9bSjx6yrLz2Mk0h6un6YLmtqql4,8
77
+ opencos_eda-0.2.43.dist-info/RECORD,,