opencos-eda 0.3.14__tar.gz → 0.3.16__tar.gz

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 (98) hide show
  1. {opencos_eda-0.3.14/opencos_eda.egg-info → opencos_eda-0.3.16}/PKG-INFO +1 -1
  2. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/DEPS.md +6 -0
  3. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/_version.py +3 -1
  4. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/_waves_pkg.sv +50 -19
  5. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/shell.py +1 -1
  6. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/sim.py +9 -5
  7. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/upload.py +2 -2
  8. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/deps/defaults.py +4 -0
  9. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/deps/deps_file.py +10 -2
  10. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/deps/deps_processor.py +96 -62
  11. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/deps_schema.py +8 -0
  12. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda.py +1 -0
  13. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_tool_helper.py +4 -4
  14. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/questa_common.py +1 -0
  15. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/riviera.py +14 -9
  16. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/util.py +5 -1
  17. {opencos_eda-0.3.14 → opencos_eda-0.3.16/opencos_eda.egg-info}/PKG-INFO +1 -1
  18. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/pyproject.toml +39 -17
  19. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/LICENSE +0 -0
  20. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/LICENSE.spdx +0 -0
  21. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/README.md +0 -0
  22. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/Architecture.md +0 -0
  23. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/ConnectingApps.md +0 -0
  24. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/Debug.md +0 -0
  25. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/DirectoryStructure.md +0 -0
  26. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/Installation.md +0 -0
  27. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/OcVivadoTcl.md +0 -0
  28. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/OpenQuestions.md +0 -0
  29. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/README.md +0 -0
  30. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/RtlCodingStyle.md +0 -0
  31. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/eda.md +0 -0
  32. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/docs/oc_cli.md +0 -0
  33. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/__init__.py +0 -0
  34. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/__init__.py +0 -0
  35. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/build.py +0 -0
  36. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/deps_help.py +0 -0
  37. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/elab.py +0 -0
  38. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/export.py +0 -0
  39. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/flist.py +0 -0
  40. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/lec.py +0 -0
  41. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/lint.py +0 -0
  42. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/multi.py +0 -0
  43. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/open.py +0 -0
  44. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/proj.py +0 -0
  45. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/sweep.py +0 -0
  46. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/synth.py +0 -0
  47. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/targets.py +0 -0
  48. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/commands/waves.py +0 -0
  49. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/deps/__init__.py +0 -0
  50. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/deps/deps_commands.py +0 -0
  51. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_base.py +0 -0
  52. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_config.py +0 -0
  53. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_config_defaults.yml +0 -0
  54. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_config_reduced.yml +0 -0
  55. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_deps_bash_completion.bash +0 -0
  56. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_deps_sanitize.py +0 -0
  57. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/eda_extract_targets.py +0 -0
  58. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/export_helper.py +0 -0
  59. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/export_json_convert.py +0 -0
  60. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/files.py +0 -0
  61. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/hw/__init__.py +0 -0
  62. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/hw/oc_cli.py +0 -0
  63. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/hw/pcie.py +0 -0
  64. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/names.py +0 -0
  65. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/peakrdl_cleanup.py +0 -0
  66. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/seed.py +0 -0
  67. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/__init__.py +0 -0
  68. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/cocotb.py +0 -0
  69. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/invio.py +0 -0
  70. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/invio_helpers.py +0 -0
  71. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/invio_yosys.py +0 -0
  72. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/iverilog.py +0 -0
  73. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/modelsim_ase.py +0 -0
  74. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/quartus.py +0 -0
  75. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/questa.py +0 -0
  76. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/questa_fe.py +0 -0
  77. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/questa_fse.py +0 -0
  78. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/slang.py +0 -0
  79. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/slang_yosys.py +0 -0
  80. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/surelog.py +0 -0
  81. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/tabbycad_yosys.py +0 -0
  82. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/verilator.py +0 -0
  83. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/vivado.py +0 -0
  84. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/tools/yosys.py +0 -0
  85. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/__init__.py +0 -0
  86. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/dict_helpers.py +0 -0
  87. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/markup_helpers.py +0 -0
  88. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/status_constants.py +0 -0
  89. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/str_helpers.py +0 -0
  90. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/subprocess_helpers.py +0 -0
  91. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/vscode_helper.py +0 -0
  92. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos/utils/vsim_helper.py +0 -0
  93. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos_eda.egg-info/SOURCES.txt +0 -0
  94. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos_eda.egg-info/dependency_links.txt +0 -0
  95. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos_eda.egg-info/entry_points.txt +0 -0
  96. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos_eda.egg-info/requires.txt +0 -0
  97. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/opencos_eda.egg-info/top_level.txt +0 -0
  98. {opencos_eda-0.3.14 → opencos_eda-0.3.16}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.3.14
3
+ Version: 0.3.16
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
@@ -9,6 +9,9 @@ METADATA: # <table> unstructured data, any UPPERCASE first level key is not cons
9
9
 
10
10
  target-spec:
11
11
 
12
+ description: # <str> optional description
13
+ info: # <str> optional description
14
+
12
15
  args: # <array or | separated str>
13
16
  - --waves
14
17
  - --sim_plusargs="+info=500"
@@ -56,6 +59,8 @@ target-spec:
56
59
  # to compile order list.
57
60
  - peakrdl: # <string> ## peakrdl command to generate CSRs
58
61
 
62
+ files: # <Identical to "deps", will append to any deps.>
63
+
59
64
  reqs: # <array or | space separated string>
60
65
  - some_file.mem # <string> aka, a non-source file required for this target.
61
66
  # This file is checked for existence prior to invoking the tool involved, for example,
@@ -100,6 +105,7 @@ target-spec:
100
105
  args: <array or | space separated string> # args to be applied if this target is used, with a matching
101
106
  # tool in 'with-tools'.
102
107
  deps: <array or | space separated string, applied with tag>
108
+ files: <identical to deps, will append to deps>
103
109
  defines: <table, applied with tag>
104
110
  plusargs: <table, applied with tag>
105
111
  parameters: <table, applied with tag>
@@ -2,6 +2,8 @@
2
2
 
3
3
  import sys
4
4
 
5
+ # pylint: disable=invalid-name
6
+
5
7
  NAME = 'opencos-eda'
6
8
 
7
9
  # Use standard library metadata module starting Python 3.8
@@ -19,4 +21,4 @@ else:
19
21
  ver = "unknown" # Or raise an error, or handle differently
20
22
 
21
23
 
22
- VERSION = ver # pylint: disable=invalid-name
24
+ VERSION = ver
@@ -26,27 +26,25 @@ package _waves_pkg;
26
26
  automatic string trace_str_value = "";
27
27
  void'($value$plusargs("trace=%s", trace_str_value));
28
28
  if (trace_str_value.tolower() == "vcd") begin
29
- $display("%t %m: Starting tracing to ./dump.vcd, plusarg +trace=%s",
30
- $realtime, trace_str_value);
29
+ $display("%t %m: Starting tracing to ./dump.vcd, plusarg +trace=vcd", $realtime);
31
30
  $dumpfile("dump.vcd");
32
31
  $dumpvars();
33
- return 1;
32
+ end else begin
33
+ $display("%t %m: Starting tracing to ./dump.fst", $realtime);
34
+ $dumpfile("dump.fst");
35
+ $dumpvars();
34
36
  end
35
37
  end
36
38
 
37
- $display("%t %m: Starting tracing to ./dump.fst", $realtime);
38
- $dumpfile("dump.fst");
39
- $dumpvars();
40
39
  return 1;
41
40
 
42
41
  endfunction : init_trace
43
42
 
44
- `elsif RIVIERA
43
+ `elsif IVERILOG
45
44
 
46
45
  bit trace_en_init = 0;
47
46
  bit trace_en = init_trace();
48
47
 
49
- // Note: must be non-automatic function for --tool=riviera
50
48
  function bit init_trace();
51
49
 
52
50
  if (trace_en_init) // only do this once.
@@ -55,26 +53,59 @@ package _waves_pkg;
55
53
  trace_en_init = 1;
56
54
 
57
55
  if ($test$plusargs("trace") != 0) begin
58
- automatic string trace_str_value = "";
56
+ $display("%t %m: Starting tracing to ./dump.vcd, plusarg +trace present", $realtime);
57
+ $dumpfile("dump.vcd");
58
+ $dumpvars();
59
+ return 1;
60
+ end
61
+
62
+ endfunction : init_trace
63
+
64
+ `endif
65
+ `endif
66
+ `endif
67
+
68
+ endpackage : _waves_pkg
69
+
70
+ //
71
+ // For RIVIERA (and SIMULATION, and not disabled):
72
+ // - it will not run system calls from a package function, unless that package was
73
+ // used by the testbench
74
+ // - so we have to
75
+ // - create a side module _waves_module. Fortunately the $dumpvars() in riviera
76
+ // dumps all module hier, not just that from _waves_module.
77
+ // - We will have to include work._waves_module in the vsim call (in riviera.py)
78
+ //
79
+
80
+ // TODO(drew): please test this on a file that doesn't involve ocsim_pkg.sv
81
+
82
+ `ifdef SIMULATION
83
+ `ifndef _WAVES_PKG_DISABLE_DUMPFILE // hook to disable this if user chooses
84
+ `ifdef RIVIERA
85
+
86
+ module _waves_module;
87
+
88
+ string trace_str_value = "";
89
+
90
+ initial begin
91
+
92
+ if ($test$plusargs("trace") != 0) begin
59
93
  void'($value$plusargs("trace=%s", trace_str_value));
60
94
  if (trace_str_value.tolower() == "vcd") begin
61
- $display("%t %m: Starting tracing to ./dump.vcd, plusarg +trace=%s",
62
- $realtime, trace_str_value);
95
+ $display("%t %m: Starting tracing to ./dump.vcd, plusarg +trace=vcd", $realtime);
63
96
  $dumpfile("dump.vcd");
64
97
  $dumpvars();
65
- return 1;
98
+ end else begin
99
+ $display("%t %m: Starting tracing to ./dump.fst", $realtime);
100
+ $dumpfile("dump.fst");
101
+ $dumpvars();
66
102
  end
67
103
  end
68
104
 
69
- $display("%t %m: Starting tracing to ./dump.fst", $realtime);
70
- $dumpfile("dump.fst");
71
- $dumpvars();
72
- return 1;
105
+ end
73
106
 
74
- endfunction : init_trace
107
+ endmodule : _waves_module
75
108
 
76
109
  `endif
77
110
  `endif
78
111
  `endif
79
-
80
- endpackage : _waves_pkg
@@ -9,7 +9,7 @@ Not intended to be overriden by Tool based classes.'''
9
9
  # These also share a lot with CommandSim.* methods, so consider refactoring to share code,
10
10
  # for example, CommandShell.do_export could move to CommandDesign, and derived classes
11
11
  # set the allow-listed args to pass to export.
12
- # pylint: disable=too-many-arguments,too-many-positional-arguments
12
+ # pylint: disable=too-many-arguments
13
13
 
14
14
  import os
15
15
 
@@ -9,7 +9,7 @@ Note that CommandSim is also a base class for opencos.commands.elab.CommandElab.
9
9
  # pylint: disable=R0801
10
10
 
11
11
  # TODO(drew): clean up CommandSim.check_logs_for_errors and CommandSim.run_commands_check_logs
12
- # pylint: disable=too-many-arguments,too-many-positional-arguments
12
+ # pylint: disable=too-many-arguments
13
13
 
14
14
  import os
15
15
  import shlex
@@ -22,6 +22,9 @@ from opencos.utils import status_constants
22
22
 
23
23
  from opencos.utils.str_helpers import strip_outer_quotes
24
24
 
25
+ THISPATH = os.path.dirname(__file__)
26
+ WAVES_PKG_SV_FNAME = str((Path(THISPATH) / '..' / '_waves_pkg.sv').resolve())
27
+
25
28
  def parameters_dict_get_command_list(
26
29
  params: dict, arg_prefix: str = '-G',
27
30
  hier_delimiter: str = '.',
@@ -638,8 +641,7 @@ class CommandSim(CommandDesign): # pylint: disable=too-many-public-methods
638
641
  break
639
642
 
640
643
  if not found_dumpfile:
641
- thispath = os.path.dirname(__file__)
642
- file_to_add = os.path.join(thispath, '..', '_waves_pkg.sv')
644
+ file_to_add = WAVES_PKG_SV_FNAME
643
645
  util.info(f'--waves arg present, no $dumpfile found, adding SV file: {file_to_add}')
644
646
  self.add_file(file_to_add)
645
647
 
@@ -706,7 +708,9 @@ class CommandSim(CommandDesign): # pylint: disable=too-many-public-methods
706
708
  if 'LICENSE_QUEUE' not in os.environ:
707
709
  os.environ['LICENSE_QUEUE'] = '1'
708
710
 
709
- def update_library_map(self, base_search_paths: list | None = None) -> None:
711
+ def update_library_map( # pylint: disable=dangerous-default-value
712
+ self, base_search_paths: list = []
713
+ ) -> None:
710
714
  '''
711
715
  Returns None, uses self.args['library-map'] to update:
712
716
 
@@ -739,7 +743,7 @@ class CommandSim(CommandDesign): # pylint: disable=too-many-public-methods
739
743
 
740
744
  # We have to go looking for lib_path though
741
745
  search_files = [lib_path]
742
- if base_search_paths and isinstance(base_search_paths, list):
746
+ if base_search_paths:
743
747
  for x in base_search_paths:
744
748
  search_files.append(Path(x) / lib_path)
745
749
  for x in search_files:
@@ -123,7 +123,7 @@ class CommandUpload(Command):
123
123
  def get_list_bitfiles(self, display: bool = True) -> list:
124
124
  '''Returns a list of bit files (ending with self.SUPPORTED_BIT_EXT)'''
125
125
 
126
- bitfiles: list[Path] = []
126
+ bitfiles = [] # list[Path]
127
127
 
128
128
  targets, files = self.get_targets_or_files_from_unparsed_args()
129
129
  targets.extend(files)
@@ -136,7 +136,7 @@ class CommandUpload(Command):
136
136
  if os.path.isfile(fullpath) and fullpath not in bitfiles:
137
137
  bitfiles.append(fullpath)
138
138
 
139
- matched: list[Path] = []
139
+ matched = [] # list[Path]
140
140
  for cand in bitfiles:
141
141
  debug(f"Looking for {cand=} in {targets=}")
142
142
  passing = all(re.search(t, str(cand)) for t in targets)
@@ -29,6 +29,8 @@ KNOWN_EDA_COMMANDS = set([
29
29
  ])
30
30
 
31
31
  SUPPORTED_TARGET_TABLE_KEYS = set([
32
+ 'description', # optional text, for DEPS.json enjoyers
33
+ 'info', # same as 'description'
32
34
  'args',
33
35
  'defines',
34
36
  'parameters',
@@ -36,6 +38,7 @@ SUPPORTED_TARGET_TABLE_KEYS = set([
36
38
  'plusargs',
37
39
  'top',
38
40
  'deps',
41
+ 'files', # identical to 'deps', will append to deps
39
42
  'reqs',
40
43
  'multi',
41
44
  'tags',
@@ -52,6 +55,7 @@ SUPPORTED_TAG_KEYS = set([
52
55
  'with-args',
53
56
  'args',
54
57
  'deps',
58
+ 'files', # identical to 'deps', will append to deps
55
59
  'reqs',
56
60
  'defines',
57
61
  'parameters',
@@ -172,6 +172,10 @@ def deps_target_get_deps_list(
172
172
  deps = entry.get(default_key, [])
173
173
  deps = dep_str2list(deps)
174
174
 
175
+ # Support for 'files' also, append to return value under 'deps'
176
+ if default_key == 'deps' and 'files' in entry:
177
+ deps += dep_str2list(entry.get('files', []))
178
+
175
179
  # Strip commented out list entries, strip blank strings, preserve non-strings
176
180
  ret = []
177
181
  for dep in deps:
@@ -204,11 +208,15 @@ def deps_list_target_sanitize(
204
208
  ret = {default_key: entry}
205
209
 
206
210
  if ret is not None:
207
- if entry_fix_deps_key and 'deps' in ret:
211
+ if entry_fix_deps_key and (('deps' in ret) or
212
+ ('files' in ret)):
208
213
  ret['deps'] = deps_target_get_deps_list(
209
214
  entry=ret, default_key='deps', deps_file=deps_file,
210
- entry_must_have_default_key=True
215
+ entry_must_have_default_key=False
211
216
  )
217
+ if 'files' in ret:
218
+ # was already appeneded to 'deps' in the ret dict
219
+ del ret['files']
212
220
  else:
213
221
  assert False, f"Can't convert to list {entry=} {default_key=} {target_node=} {deps_file=}"
214
222
 
@@ -4,8 +4,11 @@ a DEPS markup files targets (applying deps, reqs, commands, tags, incdirs, defin
4
4
  CommandDesign ref object
5
5
  '''
6
6
 
7
+ # pylint: disable=too-many-lines
8
+
7
9
  import argparse
8
10
  import copy
11
+ import glob
9
12
  import os
10
13
 
11
14
  from opencos import files
@@ -418,7 +421,8 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
418
421
  self.process_commands()
419
422
  elif key == 'reqs':
420
423
  self.process_reqs()
421
- elif key == 'deps':
424
+ elif key == 'deps' or \
425
+ (key == 'files' and 'deps' not in self.deps_entry):
422
426
  remaining_deps_list += self.process_deps_return_discovered_deps()
423
427
 
424
428
  if self.command_design_ref.tool_changed_respawn:
@@ -613,7 +617,8 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
613
617
  deps_file=self.deps_file)
614
618
  self.apply_reqs(reqs_list)
615
619
 
616
- elif key == 'deps':
620
+ elif key == 'deps' or \
621
+ (key == 'files' and 'deps' not in tags_dict_to_apply):
617
622
 
618
623
  # apply deps (includes commands, stray +define+ +incdir+)
619
624
  # treat the same way we treat self.process_deps_return_discovered_deps
@@ -861,6 +866,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
861
866
  '''Returns list of deps targets to continue processing,
862
867
 
863
868
  -- iterates through 'deps' for this target (self.deps_entry['deps'])
869
+ -- note this will also append 'files' if that table key + list/str exists.
864
870
  -- applies to self.command_design_ref
865
871
  '''
866
872
 
@@ -872,7 +878,9 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
872
878
  )
873
879
  return self.get_remaining_and_apply_deps(deps)
874
880
 
875
- def get_remaining_and_apply_deps(self, deps:list) -> list:
881
+ def get_remaining_and_apply_deps(
882
+ self, deps: list
883
+ ) -> list:
876
884
  '''Given a list of deps, process what is supported in a "deps:" table in DEPS
877
885
  markup file.'''
878
886
 
@@ -880,66 +888,98 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
880
888
 
881
889
  # Process deps (list)
882
890
  for dep in deps:
891
+ deps_targets_to_resolve.extend(
892
+ self._get_remaining_and_apply_single_dep(dep)
893
+ )
894
+ return deps_targets_to_resolve
895
+
883
896
 
884
- typ = type(dep)
885
- if typ not in SUPPORTED_DEP_KEYS_BY_TYPE:
886
- self.error(f'{self.target_node=} {dep=} in {self.deps_file=}:' \
887
- + f'has unsupported {type(dep)=} {SUPPORTED_DEP_KEYS_BY_TYPE=}')
888
-
889
- for supported_values in SUPPORTED_DEP_KEYS_BY_TYPE.values():
890
- if '*' in supported_values:
891
- continue
892
- if typ in [dict,list] and any(k not in supported_values for k in dep):
893
- self.error(
894
- f'{self.target_node=} {dep=} in {self.deps_file=}: has dict-key or',
895
- f'list-item not in {SUPPORTED_DEP_KEYS_BY_TYPE[typ]=}'
896
- )
897
-
898
- # In-line commands in the deps list, in case the results need to be in strict file
899
- # order for other deps
900
- if isinstance(dep, dict) and 'commands' in dep:
901
-
902
- commands = dep['commands']
903
- debug(f"Got commands {dep=} for in {self.caller_info}, {commands=}")
904
-
905
- assert isinstance(commands, list), \
906
- f'dep commands must be a list: {dep=} in {self.caller_info}'
907
-
908
- # For this, we need to get the returned commands (to keep strict order w/ other
909
- # deps)
910
- command_tuple = self.get_commands( commands=commands, dep=dep )
911
- # TODO(drew): it might be cleaner to return a dict instead of list, b/c those
912
- # are also ordered and we can pass type information, something like:
913
- deps_targets_to_resolve.append(command_tuple)
914
-
915
-
916
- elif isinstance(dep, str) and \
917
- any(dep.startswith(x) for x in ['+define+', '+incdir+']) and \
918
- self.is_command_design:
919
- # Note: we still support +define+ and +incdir in the deps list.
920
- # check for compile-time Verilog style plusarg, which are supported under targets
921
- # These are not run-time Verilog style plusargs comsumable from within the .sv:
922
- debug(f"Got plusarg (define, incdir) {dep=} for {self.caller_info}")
923
- self.command_design_ref.process_plusarg(plusarg=dep, pwd=self.target_path)
897
+ def _get_remaining_and_apply_single_dep( # pylint: disable=too-many-branches
898
+ self, dep: str
899
+ ) -> list:
900
+ '''Given a single dep, process is and return targets/files that need resolving'''
924
901
 
902
+ deps_targets_to_resolve = []
903
+ typ = type(dep)
904
+ if typ not in SUPPORTED_DEP_KEYS_BY_TYPE:
905
+ self.error(f'{self.target_node=} {dep=} in {self.deps_file=}:' \
906
+ + f'has unsupported {type(dep)=} {SUPPORTED_DEP_KEYS_BY_TYPE=}')
907
+
908
+ for supported_values in SUPPORTED_DEP_KEYS_BY_TYPE.values():
909
+ if '*' in supported_values:
910
+ continue
911
+ if typ in [dict,list] and any(k not in supported_values for k in dep):
912
+ self.error(
913
+ f'{self.target_node=} {dep=} in {self.deps_file=}: has dict-key or',
914
+ f'list-item not in {SUPPORTED_DEP_KEYS_BY_TYPE[typ]=}'
915
+ )
916
+
917
+ # In-line commands in the deps list, in case the results need to be in strict file
918
+ # order for other deps
919
+ if isinstance(dep, dict) and 'commands' in dep:
920
+
921
+ commands = dep['commands']
922
+ debug(f"Got commands {dep=} for in {self.caller_info}, {commands=}")
923
+
924
+ assert isinstance(commands, list), \
925
+ f'dep commands must be a list: {dep=} in {self.caller_info}'
926
+
927
+ # For this, we need to get the returned commands (to keep strict order w/ other
928
+ # deps)
929
+ command_tuple = self.get_commands( commands=commands, dep=dep )
930
+ # TODO(drew): it might be cleaner to return a dict instead of list, b/c those
931
+ # are also ordered and we can pass type information, something like:
932
+ deps_targets_to_resolve.append(command_tuple)
933
+
934
+
935
+ elif isinstance(dep, str) and \
936
+ any(dep.startswith(x) for x in ['+define+', '+incdir+']) and \
937
+ self.is_command_design:
938
+ # Note: we still support +define+ and +incdir in the deps list.
939
+ # check for compile-time Verilog style plusarg, which are supported under targets
940
+ # These are not run-time Verilog style plusargs comsumable from within the .sv:
941
+ debug(f"Got plusarg (define, incdir) {dep=} for {self.caller_info}")
942
+ self.command_design_ref.process_plusarg(plusarg=dep, pwd=self.target_path)
943
+
944
+ else:
945
+ # If we made it this far, dep better be a str type.
946
+ assert isinstance(dep, str), f'{dep=} {type(dep)=} must be str'
947
+ dep_path = self.correct_a_deps_target(target=dep, deps_dir=self.target_path)
948
+ debug(f"Got dep {dep_path=} for in {self.caller_info}")
949
+
950
+ if self.is_command_design and \
951
+ dep_path in self.command_design_ref.targets_dict or \
952
+ dep_path in deps_targets_to_resolve:
953
+ debug(f" - already processed ({dep_path}), skipping")
925
954
  else:
926
- # If we made it this far, dep better be a str type.
927
- assert isinstance(dep, str), f'{dep=} {type(dep)=} must be str'
928
- dep_path = self.correct_a_deps_target(target=dep, deps_dir=self.target_path)
929
- debug(f"Got dep {dep_path=} for in {self.caller_info}")
930
-
931
- if self.is_command_design and \
932
- dep_path in self.command_design_ref.targets_dict or \
933
- dep_path in deps_targets_to_resolve:
934
- debug(" - already processed, skipping")
935
- else:
955
+ # This is where we support files/deps file wildcards via glob syntax.
956
+ # If glob found none, we fall back to a single-file or target
957
+ glob_added_from_dep_path = False
958
+ if any(x in dep_path for x in ('*', '?', '[')):
959
+ try:
960
+ glob_list = glob.glob(dep_path)
961
+ for fpath in glob_list:
962
+ file_exists, _, _ = files.get_source_file(fpath)
963
+ if file_exists:
964
+ debug(f" - raw file ({fpath}), from glob ({dep_path}) adding",
965
+ "to return list...")
966
+ deps_targets_to_resolve.append(fpath) # append
967
+ glob_added_from_dep_path = True
968
+ if glob_list and not glob_added_from_dep_path:
969
+ self.error(f'No files were expanded from glob: {dep_path} in',
970
+ f'{self.caller_info}')
971
+ except Exception as e:
972
+ self.error(f'Unable to add files via glob {dep_path}, in',
973
+ f'{self.caller_info}exception {e}')
974
+
975
+ if not glob_added_from_dep_path:
936
976
  file_exists, _, _ = files.get_source_file(dep_path)
937
977
  if file_exists:
938
- debug(" - raw file, adding to return list...")
978
+ debug(f" - raw file ({dep_path}), adding to return list...")
939
979
  deps_targets_to_resolve.append(dep_path) # append, keeping file order.
940
980
  else:
941
- debug(" - a target (not a file) needing to be resolved, adding to return",
942
- "list...")
981
+ debug(f" - a target non-file ({dep_path}) needs to be resolved,",
982
+ "adding to return list...")
943
983
  deps_targets_to_resolve.append(dep_path) # append, keeping file order.
944
984
 
945
985
  # We return the list of deps or files that still need to be resolved
@@ -947,12 +987,6 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
947
987
  # items in this list are either:
948
988
  # -- string (dep or file)
949
989
  # -- tuple (unprocessed commands, in form: (shell_commands_list, work_dir_add_srcs_list))
950
- # TODO(drew): it might be cleaner to return a dict instead of list, b/c those are also
951
- # ordered and we can pass type information, something like:
952
- # { dep1: 'file',
953
- # dep2: 'target',
954
- # dep3: 'command_tuple',
955
- # }
956
990
  return deps_targets_to_resolve
957
991
 
958
992
 
@@ -264,6 +264,9 @@ TARGET_TAGS_TABLE = {
264
264
  TARGET_CONTENTS = Or(
265
265
  ARRAY_OR_SPACE_SEPARATED_STRING,
266
266
  {
267
+ # description, info: str
268
+ Optional('description'): Or(str, type(None)),
269
+ Optional('info'): Or(str, type(None)),
267
270
  # args: array
268
271
  Optional('args'): ARRAY_OR_SPACE_SEPARATED_STRING,
269
272
  # commands: array
@@ -285,7 +288,9 @@ TARGET_CONTENTS = Or(
285
288
  # top: string
286
289
  Optional('top'): str,
287
290
  # deps: array
291
+ # AND/OR files: array
288
292
  Optional('deps'): TARGET_DEPS_CONTENTS,
293
+ Optional('files'): TARGET_DEPS_CONTENTS,
289
294
  # reqs: array
290
295
  Optional('reqs'): ARRAY_OR_SPACE_SEPARATED_STRING,
291
296
  # multi: table
@@ -334,6 +339,8 @@ FILE_SIMPLIFIED = Schema(
334
339
  Optional('METADATA'): dict,
335
340
  Optional(str): Or( # User named target contents
336
341
  {
342
+ Optional('description'): str,
343
+ Optional('info'): str,
337
344
  Optional('args'): [str],
338
345
  Optional('defines'): {
339
346
  Optional(str): Or(type(None), int, str),
@@ -347,6 +354,7 @@ FILE_SIMPLIFIED = Schema(
347
354
  Optional('incdirs'): [str],
348
355
  Optional('top'): str,
349
356
  Optional('deps'): [str],
357
+ Optional('files'): [str],
350
358
  Optional('reqs'): [str],
351
359
  }
352
360
  )
@@ -801,6 +801,7 @@ def main(*args):
801
801
  # And show python version:
802
802
  util.info(f'python: version {sys.version_info.major}.{sys.version_info.minor}.'
803
803
  f'{sys.version_info.micro}')
804
+ util.info(f'eda from: {__file__}')
804
805
 
805
806
  # Handle --config-yml= arg
806
807
  config, unparsed = eda_config.get_eda_config(unparsed)
@@ -111,8 +111,8 @@ def get_handler_tool_version(tool: str, eda_command: str, config: dict) -> str:
111
111
 
112
112
 
113
113
 
114
- def get_handler_info_with_versions( # pylint: disable=too-many-branches
115
- config: dict | None = None,
114
+ def get_handler_info_with_versions( # pylint: disable=too-many-branches,dangerous-default-value
115
+ config: dict = {},
116
116
  include_commands: bool = True,
117
117
  sort: bool = True
118
118
  ) -> str:
@@ -202,8 +202,8 @@ def get_handler_info_with_versions( # pylint: disable=too-many-branches
202
202
  return info
203
203
 
204
204
 
205
- def pretty_info_handler_tools(
206
- info: dict | None = None, config: dict | None = None, command: str | None = ''
205
+ def pretty_info_handler_tools( # pylint: disable=dangerous-default-value
206
+ info: dict = {}, config: dict = {}, command: str = ''
207
207
  ) -> None:
208
208
  '''Pretty print (via util.info) the result from get_handler_info_with_versions()
209
209
 
@@ -151,6 +151,7 @@ class CommonSimQuesta(CommandSim, ToolQuesta):
151
151
  def prepare_compile(self):
152
152
  self.set_tool_defines()
153
153
  self.update_library_map()
154
+ self.add_waves_pkg_file()
154
155
  self.write_vlog_dot_f()
155
156
  self.write_vsim_dot_do(dot_do_to_write='all')
156
157
 
@@ -14,6 +14,7 @@ from pathlib import Path
14
14
  from opencos import util
15
15
  from opencos.commands import CommandFList
16
16
  from opencos.files import safe_shutil_which
17
+ from opencos.commands.sim import WAVES_PKG_SV_FNAME
17
18
  from opencos.tools.questa_common import ToolQuesta, CommonSimQuesta
18
19
  from opencos.utils.str_helpers import sanitize_defines_for_sh
19
20
  from opencos.utils import status_constants
@@ -101,8 +102,10 @@ class CommandSimRiviera(CommonSimQuesta, ToolRiviera):
101
102
  ' tcl steps are (from tool config in --config-yml): '
102
103
  ) + '; '.join(self.tool_config.get('simulate-coverage-tcl', [])),
103
104
  'uvm': (
104
- 'Attempts to support UVM. Adds to vlog: -l uvm +incdir+PATH for the PATH to'
105
- ' uvm_macros.svh for the installed version of Riviera used.'
105
+ 'Attempts to support UVM. For Riviera, this adds "-uvmver NUMBER -dbg" to vlog.f.'
106
+ ' You can choose your uvmver using eda arg --uvm-version=NUMBER.'
107
+ ' Also adds +access +r to vopt/vsim. There is no -l or -L library modifications,'
108
+ ' we rely on Riviera to handle this internally based on running: vlog -uvm'
106
109
  ),
107
110
  'license-queue': (
108
111
  'Set to enable env vars (if unset) LICENSE_QUEUE=1, ALDEC_LICENSE_QUEUE=1,'
@@ -127,8 +130,6 @@ class CommandSimRiviera(CommonSimQuesta, ToolRiviera):
127
130
  def compile(self):
128
131
  '''Override for CommandSimModelsimAse.compile() so we can set our own must_strings'''
129
132
 
130
- self.add_waves_pkg_file()
131
-
132
133
  if self.args['stop-before-compile']:
133
134
  # don't run anything, save everyting we've already run in _prep_compile()
134
135
  return
@@ -240,7 +241,7 @@ class CommandSimRiviera(CommonSimQuesta, ToolRiviera):
240
241
 
241
242
 
242
243
 
243
- def write_vsim_dot_do( # pylint: disable=too-many-branches,too-many-locals
244
+ def write_vsim_dot_do( # pylint: disable=too-many-branches,too-many-locals,too-many-statements
244
245
  self, dot_do_to_write: list
245
246
  ) -> None:
246
247
  '''Writes files(s) based on dot_do_to_write(list of str)
@@ -296,6 +297,10 @@ class CommandSimRiviera(CommonSimQuesta, ToolRiviera):
296
297
  f" {voptargs_str} {vsim_ext_args} {vsim_libs} work.{self.args['top']}"
297
298
  )
298
299
 
300
+ if self.args['waves'] and WAVES_PKG_SV_FNAME in self.files:
301
+ # kind of a hack, but add _waves_module (from _waves_pkg.sv) if that file
302
+ # was in our files list.
303
+ vsim_one_liner += ' work._waves_module'
299
304
 
300
305
  for l in self.args['add-top-library']:
301
306
  vsim_one_liner += f' {l}'
@@ -424,14 +429,14 @@ class CommandSimRiviera(CommonSimQuesta, ToolRiviera):
424
429
 
425
430
  return ' '.join(vsim_suppress_list)
426
431
 
427
- def update_library_map(self, base_search_paths: list | None = None) -> None:
432
+ def update_library_map( # pylint: disable=dangerous-default-value
433
+ self, base_search_paths: list = []
434
+ ) -> None:
428
435
  '''Override from sim::CommandSim
429
436
 
430
437
  We add some common places to look relative to the Riviera install paths
431
438
  '''
432
- bsp = []
433
- if isinstance(base_search_paths, list):
434
- bsp += base_search_paths
439
+ bsp = [] + base_search_paths
435
440
  bsp += [
436
441
  Path(self.sim_exe_base_path),
437
442
  Path(self.sim_exe_base_path) / '..',
@@ -20,6 +20,7 @@ from importlib import import_module
20
20
  from dotenv import load_dotenv
21
21
  from supports_color import supportsColor
22
22
 
23
+ import opencos
23
24
  from opencos.files import safe_shutil_which
24
25
  from opencos.utils import status_constants
25
26
  from opencos.utils.str_helpers import strip_ansi_color
@@ -359,7 +360,10 @@ def get_argparser() -> argparse.ArgumentParser:
359
360
  # boolean actions:
360
361
  bool_action_kwargs = get_argparse_bool_action_kwargs()
361
362
 
362
- parser.add_argument('--version', default=False, action='store_true')
363
+ parser.add_argument('--version', default=False, action='store_true',
364
+ help=('Shows our version:'
365
+ f' {opencos.__version__} ({opencos.__pyproject_name__})')
366
+ )
363
367
  parser.add_argument('--color', **bool_action_kwargs, default=bool(supportsColor.stdout),
364
368
  help='Use shell colors for info/warning/error messaging')
365
369
  parser.add_argument('--emoji', **bool_action_kwargs, default=args['emoji'],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.3.14
3
+ Version: 0.3.16
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  [project]
4
4
  name = "opencos-eda"
5
- version = "0.3.14"
5
+ version = "0.3.16"
6
6
  dependencies = [
7
7
  # opencos/eda.py dependencies
8
8
  "mergedeep >= 1.3.4",
@@ -46,16 +46,39 @@ docs = [
46
46
  [project.urls]
47
47
  Homepage = "https://github.com/cognichip/opencos"
48
48
 
49
+ #
50
+ # UV suggestions
51
+ #
52
+
53
+ # This is supposed to prevent 'uv sync' from making the project editable,
54
+ # but uv is stupid and ignores this. We'll have to remember to use
55
+ # uv sync --no-editable --upgrade
56
+ # If you want editable mode (discouraged by authors!) use:
57
+ # uv sync --editable
58
+ # (and/or)
59
+ # uv pip install -e .
60
+ # Note if you run locally in the repo-root,
61
+ [tool.uv]
62
+ package = true
63
+
64
+ #
65
+ # setuptools stuff
66
+ #
67
+
68
+ [build-system]
69
+ requires = ["setuptools"]
70
+ build-backend = "setuptools.build_meta"
71
+
49
72
  [tool.setuptools]
50
73
  # Only include these packages
51
74
  packages = [
52
- "opencos",
53
- "opencos.commands",
54
- "opencos.deps",
55
- "opencos.hw",
56
- "opencos.tools",
57
- "opencos.utils",
58
- "opencos.docs", # mapped from ./docs
75
+ "opencos",
76
+ "opencos.commands",
77
+ "opencos.deps",
78
+ "opencos.hw",
79
+ "opencos.tools",
80
+ "opencos.utils",
81
+ "opencos.docs", # mapped from ./docs
59
82
  ]
60
83
 
61
84
  [tool.setuptools.package-dir]
@@ -65,13 +88,17 @@ packages = [
65
88
  [tool.setuptools.package-data]
66
89
  # Only include certain data
67
90
  "*" = [
68
- "*.py",
69
- "eda_config*.yml",
70
- "_waves*pkg.sv",
71
- "eda_deps_bash_completion.bash",
91
+ "*.py",
92
+ "eda_config*.yml",
93
+ "_waves*pkg.sv",
94
+ "eda_deps_bash_completion.bash",
72
95
  ]
73
96
  "opencos.docs" = ["*.md"]
74
97
 
98
+ #
99
+ # Executable scripts:
100
+ #
101
+
75
102
  [project.scripts]
76
103
  eda = "opencos.eda:main_cli"
77
104
  oc_cli = "opencos.hw.oc_cli:main"
@@ -83,8 +110,3 @@ eda_deps_schema = "opencos.deps_schema:main"
83
110
  eda_deps_sanitize = "opencos.eda_deps_sanitize:main"
84
111
  # For showing instructions on bash (tab) autocomplete
85
112
  eda_show_autocomplete = "opencos.eda:main_show_autocomplete_instructions"
86
-
87
-
88
- [build-system]
89
- requires = ["setuptools"]
90
- build-backend = "setuptools.build_meta"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes