opencos-eda 0.3.0__py3-none-any.whl → 0.3.2__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/deps/deps_file.py +53 -26
- opencos/deps/deps_processor.py +79 -3
- opencos/eda_base.py +66 -20
- opencos/eda_config_defaults.yml +3 -0
- opencos/files.py +1 -0
- opencos/tests/helpers.py +17 -6
- opencos/tests/test_eda.py +3 -13
- opencos/tests/test_tools.py +6 -8
- opencos/util.py +52 -8
- {opencos_eda-0.3.0.dist-info → opencos_eda-0.3.2.dist-info}/METADATA +1 -1
- {opencos_eda-0.3.0.dist-info → opencos_eda-0.3.2.dist-info}/RECORD +16 -16
- {opencos_eda-0.3.0.dist-info → opencos_eda-0.3.2.dist-info}/WHEEL +0 -0
- {opencos_eda-0.3.0.dist-info → opencos_eda-0.3.2.dist-info}/entry_points.txt +0 -0
- {opencos_eda-0.3.0.dist-info → opencos_eda-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {opencos_eda-0.3.0.dist-info → opencos_eda-0.3.2.dist-info}/licenses/LICENSE.spdx +0 -0
- {opencos_eda-0.3.0.dist-info → opencos_eda-0.3.2.dist-info}/top_level.txt +0 -0
opencos/deps/deps_file.py
CHANGED
|
@@ -249,8 +249,11 @@ class DepsFile:
|
|
|
249
249
|
self.rel_deps_file = os.path.join(os.path.relpath(deps_path), deps_leaf)
|
|
250
250
|
|
|
251
251
|
self.error = getattr(command_design_ref, 'error', None)
|
|
252
|
+
self.error_ifarg = getattr(command_design_ref, 'error_ifarg', None)
|
|
252
253
|
if not self.error:
|
|
253
254
|
self.error = util.error
|
|
255
|
+
if not self.error_ifarg:
|
|
256
|
+
self.error_ifarg = util.error
|
|
254
257
|
|
|
255
258
|
|
|
256
259
|
def found(self) -> bool:
|
|
@@ -287,7 +290,9 @@ class DepsFile:
|
|
|
287
290
|
f'{targets_str}'))
|
|
288
291
|
|
|
289
292
|
|
|
290
|
-
def lookup(
|
|
293
|
+
def lookup( # pylint: disable=too-many-branches
|
|
294
|
+
self, target_node: str, caller_info: str
|
|
295
|
+
) -> bool:
|
|
291
296
|
'''Returns True if the target_node is in the DEPS markup file. If not, error with
|
|
292
297
|
|
|
293
298
|
some caller_info(str). This is more useful for YAML or TOML markup where we have
|
|
@@ -295,16 +300,20 @@ class DepsFile:
|
|
|
295
300
|
'''
|
|
296
301
|
if target_node not in self.data:
|
|
297
302
|
found_target = False
|
|
298
|
-
# For error printing, prefer relative paths:
|
|
299
|
-
t_path = os.path.relpath(self.target_path) + os.path.sep
|
|
300
|
-
t_node = target_node
|
|
301
|
-
t_full = os.path.join(t_path, t_node)
|
|
302
303
|
|
|
303
304
|
if target_node.startswith('-'):
|
|
304
305
|
# likely an unparsed arg that made it this far.
|
|
305
306
|
util.warning(f"Ignoring unparsed argument '{target_node}'")
|
|
306
307
|
return False
|
|
307
308
|
|
|
309
|
+
# For error printing, prefer relative paths:
|
|
310
|
+
if self.target_path:
|
|
311
|
+
t_path = os.path.relpath(self.target_path) + os.path.sep
|
|
312
|
+
else:
|
|
313
|
+
t_path = ''
|
|
314
|
+
t_node = target_node
|
|
315
|
+
t_full = os.path.join(t_path, t_node)
|
|
316
|
+
|
|
308
317
|
if not is_valid_target_name(target_node):
|
|
309
318
|
util.warning(
|
|
310
319
|
f"In file {self.rel_deps_file}, {target_node} {VALID_TARGET_INFO_STR}"
|
|
@@ -314,19 +323,28 @@ class DepsFile:
|
|
|
314
323
|
# If we don't have caller_info, likely came from command line (or DEPS JSON data):
|
|
315
324
|
if '.' in target_node:
|
|
316
325
|
# Likely a filename (target_node does not include path)
|
|
317
|
-
self.
|
|
318
|
-
|
|
319
|
-
|
|
326
|
+
self.error_ifarg(
|
|
327
|
+
f'Trying to resolve command-line target={t_full} (file?):',
|
|
328
|
+
f'File={t_node} not found in directory={t_path}',
|
|
329
|
+
arg='error-unknown-args',
|
|
330
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
331
|
+
)
|
|
320
332
|
elif not self.rel_deps_file:
|
|
321
333
|
# target, but there's no DEPS file
|
|
322
|
-
self.
|
|
323
|
-
|
|
324
|
-
|
|
334
|
+
self.error_ifarg(
|
|
335
|
+
f'Trying to resolve command-line target={t_full}:',
|
|
336
|
+
f'but path {t_path} has no DEPS markup file (DEPS.yml)',
|
|
337
|
+
arg='error-unknown-args',
|
|
338
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
339
|
+
)
|
|
325
340
|
else:
|
|
326
341
|
self.warning_show_available_targets()
|
|
327
|
-
self.
|
|
328
|
-
|
|
329
|
-
|
|
342
|
+
self.error_ifarg(
|
|
343
|
+
f'Trying to resolve command-line target={t_full}:',
|
|
344
|
+
f'was not found in deps_file={self.rel_deps_file}',
|
|
345
|
+
arg='error-unknown-args',
|
|
346
|
+
error_code=EDA_DEPS_TARGET_NOT_FOUND
|
|
347
|
+
)
|
|
330
348
|
|
|
331
349
|
else:
|
|
332
350
|
# If we have caller_info, then this was a recursive call from another
|
|
@@ -334,22 +352,31 @@ class DepsFile:
|
|
|
334
352
|
|
|
335
353
|
if '.' in target_node:
|
|
336
354
|
# Likely a filename (target_node does not include path)
|
|
337
|
-
self.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
355
|
+
self.error_ifarg(
|
|
356
|
+
f'Trying to resolve target={t_full} (file?):',
|
|
357
|
+
f'called from {caller_info},',
|
|
358
|
+
f'File={t_node} not found in directory={t_path}',
|
|
359
|
+
arg='error-unknown-args',
|
|
360
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
361
|
+
)
|
|
341
362
|
elif not self.rel_deps_file:
|
|
342
363
|
# target, but there's no DEPS file
|
|
343
|
-
self.
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
364
|
+
self.error_ifarg(
|
|
365
|
+
f'Trying to resolve target={t_full}:',
|
|
366
|
+
f'called from {caller_info},',
|
|
367
|
+
f'but {t_path} has no DEPS markup file (DEPS.yml)',
|
|
368
|
+
arg='error-unknown-args',
|
|
369
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
370
|
+
)
|
|
347
371
|
else:
|
|
348
372
|
self.warning_show_available_targets()
|
|
349
|
-
self.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
373
|
+
self.error_ifarg(
|
|
374
|
+
f'Trying to resolve target={t_full}:',
|
|
375
|
+
f'called from {caller_info},',
|
|
376
|
+
f'Target not found in deps_file={self.rel_deps_file}',
|
|
377
|
+
arg='error-unknown-args',
|
|
378
|
+
error_code=EDA_DEPS_TARGET_NOT_FOUND
|
|
379
|
+
)
|
|
353
380
|
else:
|
|
354
381
|
debug(f'Found {target_node=} in deps_file={self.rel_deps_file}')
|
|
355
382
|
found_target = True
|
opencos/deps/deps_processor.py
CHANGED
|
@@ -4,11 +4,13 @@ a DEPS markup files targets (applying deps, reqs, commands, tags, incdirs, defin
|
|
|
4
4
|
CommandDesign ref object
|
|
5
5
|
'''
|
|
6
6
|
|
|
7
|
+
import argparse
|
|
7
8
|
import os
|
|
8
9
|
|
|
9
10
|
from opencos import files
|
|
10
11
|
from opencos import eda_config
|
|
11
|
-
from opencos.util import debug, info, warning, error
|
|
12
|
+
from opencos.util import debug, info, warning, error, read_tokens_from_dot_f, \
|
|
13
|
+
patch_args_for_dir
|
|
12
14
|
from opencos.utils.str_helpers import dep_str2list
|
|
13
15
|
from opencos.deps.deps_file import deps_target_get_deps_list
|
|
14
16
|
from opencos.deps.deps_commands import deps_commands_handler
|
|
@@ -48,6 +50,7 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
48
50
|
self.target_path = target_path
|
|
49
51
|
self.target_node = target_node # for debug
|
|
50
52
|
self.deps_file = deps_file # for debug
|
|
53
|
+
self.deps_dir, _ = os.path.split(deps_file)
|
|
51
54
|
self.caller_info = caller_info
|
|
52
55
|
|
|
53
56
|
assert isinstance(deps_entry, dict), \
|
|
@@ -150,7 +153,9 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
150
153
|
return tokens
|
|
151
154
|
|
|
152
155
|
|
|
153
|
-
def apply_args(
|
|
156
|
+
def apply_args( # pylint: disable=too-many-locals,too-many-branches
|
|
157
|
+
self, args_list:list
|
|
158
|
+
) -> list:
|
|
154
159
|
'''Given args_list, applies them to our self.command_design_ref obj
|
|
155
160
|
|
|
156
161
|
This will return unparsed args that weren't in the self.command_design_ref.args keys
|
|
@@ -162,10 +167,54 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
162
167
|
f"in {self.caller_info}")
|
|
163
168
|
tokens = dep_str2list(args_list)
|
|
164
169
|
|
|
170
|
+
# patch args relative to the DEPS (if self.deps_dir exists) so things like
|
|
171
|
+
# --build-tcl=<file> for relative <file> works when calling targets from any directory.
|
|
172
|
+
tokens = patch_args_for_dir(
|
|
173
|
+
tokens=tokens, patch_dir=self.deps_dir, caller_info=self.caller_info
|
|
174
|
+
)
|
|
175
|
+
|
|
165
176
|
# We're going to run an ArgumentParser here, which is not the most efficient
|
|
166
177
|
# thing to do b/c it runs on all of self.command_design_ref.args (dict) even
|
|
167
178
|
# if we're applying a single token.
|
|
168
179
|
|
|
180
|
+
# Since some args (util.py, eda_config.py, eda.py) can only be handled from command
|
|
181
|
+
# line, it would be nice if -f or --input-file is handled from DEPS, so we'll special
|
|
182
|
+
# case that now. Recursively resolve -f / --input-file.
|
|
183
|
+
parser = argparse.ArgumentParser(
|
|
184
|
+
prog='deps_processor -f/--input-file', add_help=False, allow_abbrev=False
|
|
185
|
+
)
|
|
186
|
+
parser.add_argument('-f', '--input-file', default=[], action='append',
|
|
187
|
+
help=(
|
|
188
|
+
'Input .f file to be expanded as eda args, defines, incdirs,'
|
|
189
|
+
' files, or targets.'
|
|
190
|
+
))
|
|
191
|
+
try:
|
|
192
|
+
parsed, unparsed = parser.parse_known_args(tokens + [''])
|
|
193
|
+
tokens2 = list(filter(None, unparsed))
|
|
194
|
+
except argparse.ArgumentError:
|
|
195
|
+
error('deps_processor -f/--input-file, problem attempting to parse_known_args for:',
|
|
196
|
+
f'{tokens}')
|
|
197
|
+
tokens2 = tokens
|
|
198
|
+
|
|
199
|
+
if parsed.input_file:
|
|
200
|
+
dotf_tokens = []
|
|
201
|
+
for filepath in parsed.input_file:
|
|
202
|
+
# Since this isn't command line, we have to assume the path is relative
|
|
203
|
+
# to this DEPS file.
|
|
204
|
+
if not os.path.isabs(filepath):
|
|
205
|
+
filepath = os.path.join(self.deps_dir, filepath)
|
|
206
|
+
dotf_tokens.extend(read_tokens_from_dot_f(
|
|
207
|
+
filepath=filepath, caller_info=self.caller_info, verbose=True
|
|
208
|
+
))
|
|
209
|
+
|
|
210
|
+
# put the .f files before the unparsed args.
|
|
211
|
+
tokens2 = dotf_tokens + tokens2
|
|
212
|
+
|
|
213
|
+
# recurse until we've resolved nested .f files.
|
|
214
|
+
return self.apply_args(args_list=tokens2)
|
|
215
|
+
|
|
216
|
+
tokens = tokens2 # if no --input-file values, keep parsing the remaining tokens2
|
|
217
|
+
|
|
169
218
|
# We have to special-case anything with --tool[=value] in tokens, otherwise
|
|
170
219
|
# the user may think they were allowed to set --tool, but in our flow the Command handler
|
|
171
220
|
# (self.command_design_ref) has already been chosen, so setting the tool can have
|
|
@@ -180,11 +229,38 @@ class DepsProcessor: # pylint: disable=too-many-instance-attributes
|
|
|
180
229
|
_, unparsed = self.command_design_ref.run_argparser_on_list(
|
|
181
230
|
tokens=tokens
|
|
182
231
|
)
|
|
232
|
+
|
|
183
233
|
# Annoying, but check for plusargs in unparsed, and have referenced CommandDesign
|
|
184
234
|
# or CommandSim class handle it with process_plusarg.
|
|
185
|
-
for arg in unparsed:
|
|
235
|
+
for arg in list(unparsed):
|
|
186
236
|
if arg.startswith('+'):
|
|
187
237
|
self.command_design_ref.process_plusarg(plusarg=arg, pwd=self.target_path)
|
|
238
|
+
unparsed.remove(arg)
|
|
239
|
+
|
|
240
|
+
# For any leftover files, or targets, attempt to process those too:
|
|
241
|
+
for arg in list(unparsed):
|
|
242
|
+
# Since this isn't command line, we have to assume for files, the path is relative
|
|
243
|
+
# to this DEPS file.
|
|
244
|
+
if os.path.isabs(arg):
|
|
245
|
+
target = arg
|
|
246
|
+
else:
|
|
247
|
+
target = os.path.join(self.deps_dir, arg)
|
|
248
|
+
|
|
249
|
+
file_exists, fpath, forced_extension = files.get_source_file(target)
|
|
250
|
+
if file_exists:
|
|
251
|
+
_, file_ext = os.path.splitext(fpath)
|
|
252
|
+
if forced_extension or file_ext:
|
|
253
|
+
self.command_design_ref.add_file(fpath, caller_info=self.caller_info,
|
|
254
|
+
forced_extension=forced_extension)
|
|
255
|
+
unparsed.remove(arg)
|
|
256
|
+
|
|
257
|
+
else:
|
|
258
|
+
if not os.path.isdir(target) and \
|
|
259
|
+
self.command_design_ref.resolve_target_core(
|
|
260
|
+
target=target, no_recursion=False, caller_info=self.caller_info,
|
|
261
|
+
error_on_not_found=False
|
|
262
|
+
):
|
|
263
|
+
unparsed.remove(arg)
|
|
188
264
|
|
|
189
265
|
if unparsed:
|
|
190
266
|
# This is only a warning - because things like CommandFlist may not have every
|
opencos/eda_base.py
CHANGED
|
@@ -230,6 +230,7 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
230
230
|
'enable-tags': [],
|
|
231
231
|
'disable-tags': [],
|
|
232
232
|
'test-mode': False,
|
|
233
|
+
'error-unknown-args': True,
|
|
233
234
|
})
|
|
234
235
|
self.args_help.update({
|
|
235
236
|
'stop-before-compile': ('stop this run before any compile (if possible for tool) and'
|
|
@@ -249,6 +250,9 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
249
250
|
' --disable-tags has higher precedence than --enable-tags.'),
|
|
250
251
|
'test-mode': ('command and tool dependent, usually stops the command early without'
|
|
251
252
|
' executing.'),
|
|
253
|
+
'error-unknown-args': (
|
|
254
|
+
'Enable errors on unknown/unparsable args, or unknown/nonexistent files, or targets'
|
|
255
|
+
),
|
|
252
256
|
})
|
|
253
257
|
self.modified_args = {}
|
|
254
258
|
self.config = copy.deepcopy(config) # avoid external modifications.
|
|
@@ -495,9 +499,12 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
495
499
|
|
|
496
500
|
# Do some minimal type handling, preserving the type(self.args[key])
|
|
497
501
|
if key not in self.args:
|
|
498
|
-
self.
|
|
499
|
-
|
|
500
|
-
|
|
502
|
+
self.error_ifarg(
|
|
503
|
+
f'set_arg, {key=} not in self.args {value=}',
|
|
504
|
+
f'({self.command_name=}, {self.__class__.__name__=})',
|
|
505
|
+
arg='error-unknown-args',
|
|
506
|
+
error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
|
|
507
|
+
)
|
|
501
508
|
|
|
502
509
|
cur_value = self.args[key]
|
|
503
510
|
|
|
@@ -692,9 +699,12 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
692
699
|
_, unparsed = self.run_argparser_on_list(tokens)
|
|
693
700
|
if process_all and unparsed:
|
|
694
701
|
self.warning_show_known_args()
|
|
695
|
-
self.
|
|
696
|
-
|
|
697
|
-
|
|
702
|
+
self.error_ifarg(
|
|
703
|
+
f"Didn't understand argument: '{unparsed=}' in",
|
|
704
|
+
f"{self.command_name=} context, {pwd=}",
|
|
705
|
+
arg='error-unknown-args',
|
|
706
|
+
error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
|
|
707
|
+
)
|
|
698
708
|
|
|
699
709
|
return unparsed
|
|
700
710
|
|
|
@@ -910,6 +920,20 @@ class Command: # pylint: disable=too-many-public-methods
|
|
|
910
920
|
lines.append(self.pretty_str_known_args(command=commands[-1])) # use last command if > 1
|
|
911
921
|
util.warning("\n".join(lines))
|
|
912
922
|
|
|
923
|
+
def error_ifarg(
|
|
924
|
+
self, *msg, arg: str, error_code: int = status_constants.EDA_COMMAND_OR_ARGS_ERROR
|
|
925
|
+
) -> None:
|
|
926
|
+
'''For errors involving an unknown --arg, they can be optionally disabled
|
|
927
|
+
|
|
928
|
+
using CLI: --no-error-unknown-args, and this method arg='error-uknown-arg'
|
|
929
|
+
|
|
930
|
+
Note if arg is not present in self.args, the error is enabled.
|
|
931
|
+
'''
|
|
932
|
+
if self.args.get(arg, True):
|
|
933
|
+
self.error(*msg, error_code=error_code)
|
|
934
|
+
else:
|
|
935
|
+
util.warning(*msg)
|
|
936
|
+
|
|
913
937
|
|
|
914
938
|
class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
915
939
|
'''CommandDesign is the eda base class for command handlers that need to track files.
|
|
@@ -1392,7 +1416,8 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1392
1416
|
return self.resolve_target_core(target, no_recursion, caller_info)
|
|
1393
1417
|
|
|
1394
1418
|
def resolve_target_core( # pylint: disable=too-many-locals,too-many-branches
|
|
1395
|
-
self, target: str, no_recursion: bool, caller_info: str = ''
|
|
1419
|
+
self, target: str, no_recursion: bool, caller_info: str = '',
|
|
1420
|
+
error_on_not_found: bool = True
|
|
1396
1421
|
) -> bool:
|
|
1397
1422
|
'''Returns True if target is found. recursive point for resolving path or DEPS markup
|
|
1398
1423
|
target names.'''
|
|
@@ -1481,14 +1506,18 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1481
1506
|
self.add_file(try_file, caller_info=f'n/a::{target}::n/a')
|
|
1482
1507
|
found_target = True
|
|
1483
1508
|
break # move on to the next target
|
|
1484
|
-
if not found_target: # if STILL not found_this_target...
|
|
1485
|
-
|
|
1486
|
-
|
|
1509
|
+
if not found_target and error_on_not_found: # if STILL not found_this_target...
|
|
1510
|
+
# allow this if --no-error-unknown-args:
|
|
1511
|
+
self.error_ifarg(
|
|
1512
|
+
f"Unable to resolve {target=}",
|
|
1513
|
+
arg='error-unknown-args',
|
|
1514
|
+
error_code=status_constants.EDA_DEPS_TARGET_NOT_FOUND
|
|
1515
|
+
)
|
|
1487
1516
|
|
|
1488
1517
|
# if we've found any target since being called, it means we found the one we were called for
|
|
1489
1518
|
return found_target
|
|
1490
1519
|
|
|
1491
|
-
def add_file(
|
|
1520
|
+
def add_file( # pylint: disable=too-many-locals,too-many-branches
|
|
1492
1521
|
self, filename: str, use_abspath: bool = True, add_to_non_sources: bool = False,
|
|
1493
1522
|
caller_info: str = '', forced_extension: str = ''
|
|
1494
1523
|
) -> str:
|
|
@@ -1512,6 +1541,7 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1512
1541
|
vhdl_file_ext_list = known_file_ext_dict.get('vhdl', [])
|
|
1513
1542
|
cpp_file_ext_list = known_file_ext_dict.get('cpp', [])
|
|
1514
1543
|
sdc_file_ext_list = known_file_ext_dict.get('synth_constraints', [])
|
|
1544
|
+
dotf_file_ext_list = known_file_ext_dict.get('dotf', [])
|
|
1515
1545
|
|
|
1516
1546
|
if forced_extension:
|
|
1517
1547
|
# If forced_extension='systemverilog', then use the first known extension for
|
|
@@ -1544,6 +1574,13 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1544
1574
|
elif file_ext in sdc_file_ext_list:
|
|
1545
1575
|
self.files_sdc.append(file_abspath)
|
|
1546
1576
|
util.debug(f"Added SDC file {filename} as {file_abspath}")
|
|
1577
|
+
elif file_ext in dotf_file_ext_list:
|
|
1578
|
+
# a stray .f file as a source file, sure why not support it:
|
|
1579
|
+
dp = DepsProcessor(command_design_ref=self, deps_entry={}, target='',
|
|
1580
|
+
target_path='', target_node='', deps_file='',
|
|
1581
|
+
caller_info=caller_info)
|
|
1582
|
+
dp.apply_args(args_list=[f'-f={file_abspath}'])
|
|
1583
|
+
del dp
|
|
1547
1584
|
else:
|
|
1548
1585
|
# unknown file extension. In these cases we link the file to the working directory
|
|
1549
1586
|
# so it is available (for example, a .mem file that is expected to exist with relative
|
|
@@ -1637,9 +1674,12 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1637
1674
|
if process_all and possible_unparsed_args:
|
|
1638
1675
|
_tool = self.safe_which_tool()
|
|
1639
1676
|
self.warning_show_known_args()
|
|
1640
|
-
self.
|
|
1641
|
-
|
|
1642
|
-
|
|
1677
|
+
self.error_ifarg(
|
|
1678
|
+
f"Didn't understand unparsed args: {possible_unparsed_args}, for command",
|
|
1679
|
+
f"'{self.command_name}', tool '{_tool}'",
|
|
1680
|
+
arg='error-unknown-args',
|
|
1681
|
+
error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
|
|
1682
|
+
)
|
|
1643
1683
|
|
|
1644
1684
|
remove_list = []
|
|
1645
1685
|
last_potential_top_file = ('', '') # (top, fpath)
|
|
@@ -1697,9 +1737,12 @@ class CommandDesign(Command): # pylint: disable=too-many-instance-attributes
|
|
|
1697
1737
|
# we were unable to figure out what this command line token is for...
|
|
1698
1738
|
if process_all and unparsed:
|
|
1699
1739
|
self.warning_show_known_args()
|
|
1700
|
-
self.
|
|
1701
|
-
|
|
1702
|
-
|
|
1740
|
+
self.error_ifarg(
|
|
1741
|
+
f"Didn't understand remaining args or targets {unparsed=} for command",
|
|
1742
|
+
f"'{self.command_name}'",
|
|
1743
|
+
arg='error-unknown-args',
|
|
1744
|
+
error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
|
|
1745
|
+
)
|
|
1703
1746
|
|
|
1704
1747
|
# handle a missing self.args['top'] with last filepath or last target:
|
|
1705
1748
|
if not self.args.get('top', ''):
|
|
@@ -2244,9 +2287,12 @@ class CommandParallel(Command):
|
|
|
2244
2287
|
bad_remaining_args = [x for x in single_cmd_unparsed if x.startswith('-')]
|
|
2245
2288
|
if bad_remaining_args:
|
|
2246
2289
|
self.warning_show_known_args(command=f'{self.command_name} {command}')
|
|
2247
|
-
self.
|
|
2248
|
-
|
|
2249
|
-
|
|
2290
|
+
self.error_ifarg(
|
|
2291
|
+
f'for {self.command_name} {command=} the following args are unknown',
|
|
2292
|
+
f'{bad_remaining_args}',
|
|
2293
|
+
arg='error-unknown-args',
|
|
2294
|
+
error_code=status_constants.EDA_COMMAND_OR_ARGS_ERROR
|
|
2295
|
+
)
|
|
2250
2296
|
|
|
2251
2297
|
# Remove unparsed args starting with '+', since those are commonly sent downstream to
|
|
2252
2298
|
# single job (example, CommandSim plusargs).
|
opencos/eda_config_defaults.yml
CHANGED
opencos/files.py
CHANGED
opencos/tests/helpers.py
CHANGED
|
@@ -9,12 +9,14 @@ from pathlib import Path
|
|
|
9
9
|
|
|
10
10
|
from contextlib import redirect_stdout, redirect_stderr
|
|
11
11
|
|
|
12
|
-
from opencos import eda
|
|
13
|
-
from opencos import deps_schema
|
|
12
|
+
from opencos import eda, eda_tool_helper, deps_schema
|
|
14
13
|
from opencos.utils.markup_helpers import yaml_safe_load
|
|
15
14
|
from opencos.utils import status_constants
|
|
16
15
|
from opencos.utils.subprocess_helpers import subprocess_run_background
|
|
17
16
|
|
|
17
|
+
# Figure out what tools the system has available, without calling eda.main(..)
|
|
18
|
+
config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
|
|
19
|
+
|
|
18
20
|
|
|
19
21
|
def eda_wrap_is_sim_fail(rc: int, quiet: bool = False) -> bool:
|
|
20
22
|
'''Because eda_wrap calls eda_main(..) and will continue running
|
|
@@ -30,11 +32,11 @@ def eda_wrap_is_sim_fail(rc: int, quiet: bool = False) -> bool:
|
|
|
30
32
|
status_constants.EDA_DEFAULT_ERROR
|
|
31
33
|
)
|
|
32
34
|
|
|
33
|
-
def can_run_eda_command(*commands,
|
|
35
|
+
def can_run_eda_command(*commands, cfg: dict = config) -> bool:
|
|
34
36
|
'''Returns True if we have any installed tool that can run: eda <command>'''
|
|
35
37
|
runnable = []
|
|
36
38
|
for command in list(commands):
|
|
37
|
-
handler =
|
|
39
|
+
handler = cfg['command_handler'].get(command, None)
|
|
38
40
|
if not handler:
|
|
39
41
|
return False
|
|
40
42
|
if handler and getattr(handler, 'CHECK_REQUIRES', []):
|
|
@@ -44,7 +46,7 @@ def can_run_eda_command(*commands, config: dict) -> bool:
|
|
|
44
46
|
# We cannot run tools that have disable-auto set:
|
|
45
47
|
tool = getattr(handler, '_TOOL', '')
|
|
46
48
|
if handler and tool:
|
|
47
|
-
entry =
|
|
49
|
+
entry = cfg['auto_tools_order'][0].get(tool, {})
|
|
48
50
|
if entry and entry.get('disable-auto', False):
|
|
49
51
|
# This tool cannot automatically run our command.
|
|
50
52
|
return False
|
|
@@ -52,6 +54,14 @@ def can_run_eda_command(*commands, config: dict) -> bool:
|
|
|
52
54
|
runnable.append(True)
|
|
53
55
|
return runnable and all(runnable)
|
|
54
56
|
|
|
57
|
+
def can_run_eda_sim(cfg: dict = config) -> bool:
|
|
58
|
+
'''Returns True if we have any installed tool that can run: eda sim'''
|
|
59
|
+
return can_run_eda_command('sim', cfg=cfg)
|
|
60
|
+
|
|
61
|
+
def can_run_eda_elab(cfg: dict = config) -> bool:
|
|
62
|
+
'''Returns True if we have any installed tool that can run: eda elab'''
|
|
63
|
+
return can_run_eda_command('elab', cfg=cfg)
|
|
64
|
+
|
|
55
65
|
def chdir_remove_work_dir(startpath, relpath):
|
|
56
66
|
'''Changes dir to startpath/relpath, removes the work directories (eda.work, eda.export*)'''
|
|
57
67
|
os.chdir(os.path.join(str(Path(startpath)), str(Path(relpath))))
|
|
@@ -171,6 +181,7 @@ class Helpers:
|
|
|
171
181
|
'''Changes directory to self.DEFAULT_DIR and removes eda.work, eda.export paths'''
|
|
172
182
|
chdir_remove_work_dir('', self.DEFAULT_DIR)
|
|
173
183
|
|
|
184
|
+
|
|
174
185
|
def _resolve_logfile(self, logfile=None) -> str:
|
|
175
186
|
'''Returns the logfile's filepath'''
|
|
176
187
|
ret = logfile
|
|
@@ -232,7 +243,7 @@ class Helpers:
|
|
|
232
243
|
return rc
|
|
233
244
|
|
|
234
245
|
def is_in_log(self, *want_str, logfile=None, windows_path_support=False):
|
|
235
|
-
'''Check if
|
|
246
|
+
'''Check if want_str (joined) is in the logfile, or self.DEFAULT_LOG'''
|
|
236
247
|
logfile = self._resolve_logfile(logfile)
|
|
237
248
|
want_str0 = ' '.join(list(want_str))
|
|
238
249
|
want_str1 = want_str0.replace('/', '\\')
|
opencos/tests/test_eda.py
CHANGED
|
@@ -23,11 +23,12 @@ import subprocess
|
|
|
23
23
|
|
|
24
24
|
import pytest
|
|
25
25
|
|
|
26
|
-
from opencos import eda
|
|
26
|
+
from opencos import eda
|
|
27
27
|
from opencos.utils.markup_helpers import yaml_safe_load
|
|
28
28
|
from opencos.tests import helpers
|
|
29
29
|
from opencos.tests.helpers import eda_wrap, eda_sim_wrap, eda_elab_wrap, \
|
|
30
|
-
Helpers
|
|
30
|
+
Helpers, tools_loaded, can_run_eda_sim
|
|
31
|
+
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
THISPATH = os.path.dirname(__file__)
|
|
@@ -36,17 +37,6 @@ def chdir_remove_work_dir(relpath):
|
|
|
36
37
|
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
37
38
|
return helpers.chdir_remove_work_dir(THISPATH, relpath)
|
|
38
39
|
|
|
39
|
-
# Figure out what tools the system has available, without calling eda.main(..)
|
|
40
|
-
config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
|
|
41
|
-
|
|
42
|
-
def can_run_eda_sim() -> bool:
|
|
43
|
-
'''Returns True if we have any installed tool that can run: eda sim'''
|
|
44
|
-
return helpers.can_run_eda_command('sim', config=config)
|
|
45
|
-
|
|
46
|
-
def can_run_eda_elab() -> bool:
|
|
47
|
-
'''Returns True if we have any installed tool that can run: eda elab'''
|
|
48
|
-
return helpers.can_run_eda_command('elab', config=config)
|
|
49
|
-
|
|
50
40
|
@pytest.mark.skipif(
|
|
51
41
|
'verilator' not in tools_loaded and 'vivado' not in tools_loaded,
|
|
52
42
|
reason="requires verilator OR vivado"
|
opencos/tests/test_tools.py
CHANGED
|
@@ -6,25 +6,23 @@ import os
|
|
|
6
6
|
import sys
|
|
7
7
|
import pytest
|
|
8
8
|
|
|
9
|
-
from opencos import eda,
|
|
9
|
+
from opencos import eda, eda_base
|
|
10
10
|
|
|
11
11
|
from opencos.tools.verilator import ToolVerilator
|
|
12
12
|
from opencos.tools.vivado import ToolVivado
|
|
13
13
|
from opencos.tools.cocotb import ToolCocotb
|
|
14
14
|
from opencos.tests import helpers
|
|
15
|
-
from opencos.tests.helpers import eda_wrap, eda_wrap_is_sim_fail
|
|
15
|
+
from opencos.tests.helpers import eda_wrap, eda_wrap_is_sim_fail, config, tools_loaded
|
|
16
16
|
from opencos.utils.markup_helpers import yaml_safe_load
|
|
17
17
|
from opencos.utils import status_constants
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
THISPATH = os.path.dirname(__file__)
|
|
21
21
|
|
|
22
22
|
def chdir_remove_work_dir(relpath):
|
|
23
23
|
'''Changes dir to relpath, removes the work directories (eda.work, eda.export*)'''
|
|
24
|
-
return helpers.chdir_remove_work_dir(
|
|
24
|
+
return helpers.chdir_remove_work_dir(THISPATH, relpath)
|
|
25
25
|
|
|
26
|
-
# Figure out what tools the system has available, without calling eda.main(..)
|
|
27
|
-
config, tools_loaded = eda_tool_helper.get_config_and_tools_loaded()
|
|
28
26
|
|
|
29
27
|
def test_tools_loaded():
|
|
30
28
|
'''Does not directly call 'eda.main' instead create a few Tool
|
|
@@ -37,7 +35,7 @@ def test_tools_loaded():
|
|
|
37
35
|
# It's possible we're running in some container or install that has no tools, for example,
|
|
38
36
|
# Windows.
|
|
39
37
|
if sys.platform.startswith('win') and \
|
|
40
|
-
not helpers.can_run_eda_command('elab', 'sim',
|
|
38
|
+
not helpers.can_run_eda_command('elab', 'sim', cfg=config):
|
|
41
39
|
# Windows, not handlers for elab or sim:
|
|
42
40
|
pass
|
|
43
41
|
else:
|
|
@@ -129,7 +127,7 @@ def test_sim_elab_tools_pass_or_fail(command, tool, target, sim_expect_pass, add
|
|
|
129
127
|
added_args = added_sim_args_str.split()
|
|
130
128
|
|
|
131
129
|
relative_dir = "deps_files/test_err_fatal"
|
|
132
|
-
os.chdir(os.path.join(
|
|
130
|
+
os.chdir(os.path.join(THISPATH, relative_dir))
|
|
133
131
|
rc = eda.main(command, '--tool', tool, *(added_args), target)
|
|
134
132
|
print(f'{rc=}')
|
|
135
133
|
if command != 'sim' or sim_expect_pass:
|
opencos/util.py
CHANGED
|
@@ -435,25 +435,67 @@ def load_env_file(env_file: str) -> None:
|
|
|
435
435
|
else:
|
|
436
436
|
warning(f'--env-file {env_file} does not exist and is not loaded.')
|
|
437
437
|
|
|
438
|
-
def
|
|
438
|
+
def patch_args_for_dir(tokens: list, patch_dir: str, caller_info: str) -> list:
|
|
439
|
+
'''Given list of args, attempt to correct for relative dir'''
|
|
440
|
+
|
|
441
|
+
# deal with relative path args or files.
|
|
442
|
+
# Note the dot-f file could have been in a different directory (-f=path/to/my.f)
|
|
443
|
+
# As a workaround to deal with relative paths, attempt to replace relative
|
|
444
|
+
# path args within this dotf contents - so they are relative the dotf dir:
|
|
445
|
+
if not os.path.isdir(patch_dir):
|
|
446
|
+
return tokens
|
|
447
|
+
|
|
448
|
+
ret = []
|
|
449
|
+
for word in tokens:
|
|
450
|
+
if word.startswith('-') and '=' in word:
|
|
451
|
+
parts = word.split('=')
|
|
452
|
+
leftarg = parts[0] + '='
|
|
453
|
+
word = '='.join(parts[1:])
|
|
454
|
+
elif word.startswith('+incdir+'):
|
|
455
|
+
# do for +incdir+ too
|
|
456
|
+
leftarg = '+incdir+'
|
|
457
|
+
word = word[len('+incdir+'):]
|
|
458
|
+
else:
|
|
459
|
+
leftarg = ''
|
|
460
|
+
|
|
461
|
+
if word and not os.path.isabs(word) and \
|
|
462
|
+
os.path.exists(os.path.join(patch_dir, word)):
|
|
463
|
+
# fix relative path of word, or --arg=word
|
|
464
|
+
word = os.path.abspath(os.path.join(patch_dir, word))
|
|
465
|
+
info(f'Using relative path {patch_dir} for arg/token: {leftarg}{word}',
|
|
466
|
+
f'{caller_info}')
|
|
467
|
+
ret.append(f'{leftarg}{word}')
|
|
468
|
+
return ret
|
|
469
|
+
|
|
470
|
+
def read_tokens_from_dot_f(filepath: str, caller_info: str = '', verbose: bool = False) -> list:
|
|
439
471
|
'''Returns list of tokens from a .f file, with ENV vars expanded'''
|
|
440
472
|
|
|
441
473
|
# Let's defer 'info' printing out what input files were opened until after
|
|
442
474
|
# args['quiet'] and debug is resolved (which may be in these .f files)
|
|
443
|
-
|
|
475
|
+
start_str = f"Opening -f / --input-file '{filepath}' for contents {caller_info}"
|
|
476
|
+
if verbose:
|
|
477
|
+
info(start_str)
|
|
478
|
+
else:
|
|
479
|
+
debug(start_str)
|
|
444
480
|
if not os.path.isfile(filepath):
|
|
445
|
-
error(f'-f (or --input-file): {filepath} does not exist',
|
|
481
|
+
error(f'-f (or --input-file): {filepath} does not exist {caller_info}',
|
|
446
482
|
error_code=status_constants.EDA_GENERAL_FILE_NOT_FOUND)
|
|
447
483
|
return []
|
|
448
484
|
if os.path.abspath(filepath) in dot_f_files_expanded:
|
|
449
485
|
error(f'-f (or --input-file): {filepath} has already been expanded',
|
|
450
|
-
'cannot traverse again (duplicate arg or nested .f files)')
|
|
486
|
+
f'cannot traverse again (duplicate arg or nested .f files) {caller_info}')
|
|
451
487
|
dot_f_files_expanded.add(os.path.abspath(filepath))
|
|
452
488
|
tokens = []
|
|
489
|
+
dotf_file_dir, _ = os.path.split(filepath)
|
|
453
490
|
with open(filepath, encoding='utf-8') as f:
|
|
454
491
|
for line in f:
|
|
455
492
|
line = os.path.expandvars(line.strip())
|
|
456
|
-
|
|
493
|
+
if not line or line.startswith('#') or line.startswith('//'):
|
|
494
|
+
continue
|
|
495
|
+
words = line.split()
|
|
496
|
+
tokens.extend(patch_args_for_dir(
|
|
497
|
+
tokens=words, patch_dir=dotf_file_dir, caller_info=f"(from dotf {filepath})"
|
|
498
|
+
))
|
|
457
499
|
return tokens
|
|
458
500
|
|
|
459
501
|
|
|
@@ -471,7 +513,7 @@ def process_debug_args(parsed: argparse.Namespace) -> None:
|
|
|
471
513
|
|
|
472
514
|
|
|
473
515
|
def process_tokens( # pylint: disable=too-many-branches
|
|
474
|
-
tokens: list
|
|
516
|
+
tokens: list, caller_info: str = ''
|
|
475
517
|
) -> (argparse.Namespace, list):
|
|
476
518
|
'''Processes tokens (unparsed args list) on util's ArgumentParser
|
|
477
519
|
|
|
@@ -517,13 +559,15 @@ def process_tokens( # pylint: disable=too-many-branches
|
|
|
517
559
|
if parsed.input_file:
|
|
518
560
|
dotf_tokens = []
|
|
519
561
|
for filepath in parsed.input_file:
|
|
520
|
-
dotf_tokens.extend(read_tokens_from_dot_f(
|
|
562
|
+
dotf_tokens.extend(read_tokens_from_dot_f(
|
|
563
|
+
filepath=filepath, caller_info=caller_info
|
|
564
|
+
))
|
|
521
565
|
|
|
522
566
|
# put the .f files before the unparsed args.
|
|
523
567
|
tokens2 = dotf_tokens + tokens2
|
|
524
568
|
|
|
525
569
|
# recurse until we've resolved nested .f files.
|
|
526
|
-
return process_tokens(tokens=tokens2)
|
|
570
|
+
return process_tokens(tokens=tokens2, caller_info=f'(from {parsed.input_file[-1]})')
|
|
527
571
|
|
|
528
572
|
|
|
529
573
|
# Continue with all normal parsing beyond --debug and -f/--input-file,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
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
|
|
@@ -3,9 +3,9 @@ opencos/_version.py,sha256=KaWIjS0c08g-C0fgYY1kXwSPqhOFxaq5pYEeoZhOR_I,617
|
|
|
3
3
|
opencos/_waves_pkg.sv,sha256=TL5YT9lT-fn2FD54MbVVZROmZ7vtW3ScA_rM2eRzKmU,2068
|
|
4
4
|
opencos/deps_schema.py,sha256=VUdXuq43mKfM-U4x7DSA28-MH1Xqxre6V7Ttw2DeOqI,16762
|
|
5
5
|
opencos/eda.py,sha256=91E-EsyZS-uRadApP-h2onW6rpvLBnrpJoT_9tRtsS8,23322
|
|
6
|
-
opencos/eda_base.py,sha256=
|
|
6
|
+
opencos/eda_base.py,sha256=jf4t11UPj39swL41z-EJiGTOnHvRScaQc-SAjpZ5XI4,109651
|
|
7
7
|
opencos/eda_config.py,sha256=z3yQOPGBX7-yKp6BdQYfJ9eOJf-Jctl-mwCDj3vj2BI,12712
|
|
8
|
-
opencos/eda_config_defaults.yml,sha256=
|
|
8
|
+
opencos/eda_config_defaults.yml,sha256=LF0yAncYeaPtZIoAfEeo2aiDXT4cjYa99soGks0WRzM,16063
|
|
9
9
|
opencos/eda_config_max_verilator_waivers.yml,sha256=lTAU4IOEbUWVlPzuer1YYhIyxpPINeA4EJqcRIT-Ymk,840
|
|
10
10
|
opencos/eda_config_reduced.yml,sha256=cQ9jY4J7EvAbeHTiP6bvpDSVJAYiitjLZPSxxLKIEbk,1440
|
|
11
11
|
opencos/eda_deps_bash_completion.bash,sha256=jMkQKY82HBgOnQeMdA1hMrXguRFtB52SMBxUemKovL4,1958
|
|
@@ -14,11 +14,11 @@ opencos/eda_extract_targets.py,sha256=POlxZfqf2dNH2nc1CEw5B_53vSHAicSTkpU9_-2_6Z
|
|
|
14
14
|
opencos/eda_tool_helper.py,sha256=_YgobDLEWW6Fzdr976LxaCDZ4DKRyuMs5CrYQHaTPrU,2558
|
|
15
15
|
opencos/export_helper.py,sha256=5BnrkhiieJBgYKAryhXD7HSGtrgvXQpZ8B5ltdrhbRY,22649
|
|
16
16
|
opencos/export_json_convert.py,sha256=tSIMbLFtc_Fo66EhFovMii1v_qJYyFZJrPNnoPdW7L0,4182
|
|
17
|
-
opencos/files.py,sha256=
|
|
17
|
+
opencos/files.py,sha256=AQOnsrvoc0r76LiFrkoMbwOGdUO1FpBiFY_jyyI_ve8,1566
|
|
18
18
|
opencos/names.py,sha256=Y2aJ5wgpbNIJ-_P5xUXnHMv_h-zMOX2Rt6iLuduqC1Q,1213
|
|
19
19
|
opencos/peakrdl_cleanup.py,sha256=vHNGtalTrIVP335PhRjPt9RhoccgpK1HJAi-E4M8Kc8,736
|
|
20
20
|
opencos/seed.py,sha256=IL9Yg-r9SLSRseMVWaEHmuw2_DNi_eyut11EafoNTsU,942
|
|
21
|
-
opencos/util.py,sha256=
|
|
21
|
+
opencos/util.py,sha256=ffaSoDDOsL6mx_fYgAyJA8fawsxZ5YHKqs67b8iW5rw,41921
|
|
22
22
|
opencos/commands/__init__.py,sha256=oOOQmn5_jHAMSOfA3swJJ7mdoyHsJA0lJwKPTudlTns,1125
|
|
23
23
|
opencos/commands/build.py,sha256=mvJYxk5J15k0Cr8R7oIdIIdsEtWV3gE-LnPweVwtSDo,1487
|
|
24
24
|
opencos/commands/deps_help.py,sha256=WDrU7H9sypzDAxe_CHqhW5B_scbQMzBEdf-v-Jcfd5Q,10682
|
|
@@ -40,22 +40,22 @@ opencos/commands/waves.py,sha256=nrp3ALwfJujZns44tgCgia_dEedQyKe0T3fuws8h39U,769
|
|
|
40
40
|
opencos/deps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
41
|
opencos/deps/defaults.py,sha256=NXh3V4oInrBVlDw64B2OCI77wzdn1NtaD64srhBnmZU,1486
|
|
42
42
|
opencos/deps/deps_commands.py,sha256=q4JfSfzRO2nM2zdNT4enCy33FokEytZYQJn1HJ6osJk,16606
|
|
43
|
-
opencos/deps/deps_file.py,sha256=
|
|
44
|
-
opencos/deps/deps_processor.py,sha256=
|
|
43
|
+
opencos/deps/deps_file.py,sha256=YQ5ftYvppRTqUto22r-XDH6-bcMO7cA-WiJ7QzPjljY,17103
|
|
44
|
+
opencos/deps/deps_processor.py,sha256=DBaMUEnpoIL4xaNPs2f2AFGcWLST5pP_Qgup9r-8D7M,41403
|
|
45
45
|
opencos/hw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
46
|
opencos/hw/oc_cli.py,sha256=U1JGlshLZhtd0LgndZFBZVltAj_HemdhbjO_Zo8ZuVM,132252
|
|
47
47
|
opencos/hw/pcie.py,sha256=VUJljaZJYgScAAx5yn7F6GoA8K9eTcw24otYZbkMpYs,3035
|
|
48
48
|
opencos/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
49
|
opencos/tests/custom_config.yml,sha256=TRoVM9ZFKPOA_8JmlpzaMhnGO1txmaD14N_8P1oqzew,257
|
|
50
|
-
opencos/tests/helpers.py,sha256=
|
|
50
|
+
opencos/tests/helpers.py,sha256=wkEzYRt78B4b7Qni2GoWcncrhWjZ3nLhDMHtPYvvW8w,11725
|
|
51
51
|
opencos/tests/test_build.py,sha256=FQAxOpLVQShAHD_L5rqJctPeSAoqoOCNFI0RXflLuY0,387
|
|
52
52
|
opencos/tests/test_deps_helpers.py,sha256=uQZxleh6aKO-mZQhagHh5xLIBbpQ8dav7-5D0eemq_g,8164
|
|
53
53
|
opencos/tests/test_deps_schema.py,sha256=T3P9KjaMyKsk8b7snNVvNSsom2hIJcg6Z9apYiXoH9Y,941
|
|
54
|
-
opencos/tests/test_eda.py,sha256=
|
|
54
|
+
opencos/tests/test_eda.py,sha256=PhAFCqoZxUhjuSvNeHpTHdwt8UhHjRdVppesgcWBX64,37407
|
|
55
55
|
opencos/tests/test_eda_elab.py,sha256=AjU4WMYtFoHpNe1Z4yWWpxDKy4V_hAjL5rl3jqphZrk,3179
|
|
56
56
|
opencos/tests/test_eda_synth.py,sha256=BtBrNVJ9C-LJt3K0wNNS5ukEVrET16AbRXl2IzxudJ8,5744
|
|
57
57
|
opencos/tests/test_oc_cli.py,sha256=w-F-LjSSWVql3D2WG8tcV4_C52i-hL_2WT3oDpKQn9s,734
|
|
58
|
-
opencos/tests/test_tools.py,sha256
|
|
58
|
+
opencos/tests/test_tools.py,sha256=JFjwq8YJPxaALbIEZUA-1VR8O_N-zmmM4ueboFEYA4Y,13589
|
|
59
59
|
opencos/tests/deps_files/command_order/DEPS.yml,sha256=PSzBBJDSU8ccCy3Ls5j_ws_vepmUkTIgWjaMjBhNbSg,806
|
|
60
60
|
opencos/tests/deps_files/error_msgs/DEPS.yml,sha256=fYvHouIscOlr8V28bqx9SoxRBpDBLX4AG-AkVXh8qbo,717
|
|
61
61
|
opencos/tests/deps_files/iverilog_test/DEPS.yml,sha256=vDylEuLt642lhRSvOr3F5ziB5lhPSwkaUGN4_mWJw-c,40
|
|
@@ -88,10 +88,10 @@ opencos/utils/str_helpers.py,sha256=726ScK5-v7QkBi-zqESKZLsOl2_ya4vVJ5ZhxJqmBFo,
|
|
|
88
88
|
opencos/utils/subprocess_helpers.py,sha256=xemAGPey6M0sWY_FElvr-Z0phCfdjaC-znP8FKihPaE,3535
|
|
89
89
|
opencos/utils/vscode_helper.py,sha256=9nHyMUIL-gzfW-qLH06sgaCnVK-YTOtu6pusitNNhL8,1363
|
|
90
90
|
opencos/utils/vsim_helper.py,sha256=1johPOGbjbMgnCDSTpgsQcSuAquiqq1Y2MBxS6WY6b4,1552
|
|
91
|
-
opencos_eda-0.3.
|
|
92
|
-
opencos_eda-0.3.
|
|
93
|
-
opencos_eda-0.3.
|
|
94
|
-
opencos_eda-0.3.
|
|
95
|
-
opencos_eda-0.3.
|
|
96
|
-
opencos_eda-0.3.
|
|
97
|
-
opencos_eda-0.3.
|
|
91
|
+
opencos_eda-0.3.2.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
92
|
+
opencos_eda-0.3.2.dist-info/licenses/LICENSE.spdx,sha256=8gn1610RMP6eFgT3Hm6q9VKXt0RvdTItL_oxMo72jII,189
|
|
93
|
+
opencos_eda-0.3.2.dist-info/METADATA,sha256=0PgS7CqBIdwYkBXPQ_6PaCFCNFKEsRz5G_owk48zkJI,666
|
|
94
|
+
opencos_eda-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
95
|
+
opencos_eda-0.3.2.dist-info/entry_points.txt,sha256=6n1T5NwVYDhN5l1h5zmyT197G4pE0SySDreB0QJzJR0,218
|
|
96
|
+
opencos_eda-0.3.2.dist-info/top_level.txt,sha256=J4JDP-LpRyJqPNeh9bSjx6yrLz2Mk0h6un6YLmtqql4,8
|
|
97
|
+
opencos_eda-0.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|