opencos-eda 0.2.54__py3-none-any.whl → 0.2.56__py3-none-any.whl

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