rtl-buddy 2.1.4__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.
- rtl_buddy/__init__.py +5 -0
- rtl_buddy/__main__.py +18 -0
- rtl_buddy/config/__init__.py +17 -0
- rtl_buddy/config/coverage.py +41 -0
- rtl_buddy/config/coverview.py +54 -0
- rtl_buddy/config/model.py +106 -0
- rtl_buddy/config/platform.py +108 -0
- rtl_buddy/config/reg.py +84 -0
- rtl_buddy/config/root.py +292 -0
- rtl_buddy/config/rtl.py +153 -0
- rtl_buddy/config/suite.py +95 -0
- rtl_buddy/config/test.py +330 -0
- rtl_buddy/config/uvm.py +19 -0
- rtl_buddy/config/verible.py +83 -0
- rtl_buddy/errors.py +14 -0
- rtl_buddy/logging_utils.py +423 -0
- rtl_buddy/rtl_buddy.py +591 -0
- rtl_buddy/runner/__init__.py +8 -0
- rtl_buddy/runner/test_results.py +95 -0
- rtl_buddy/runner/test_runner.py +135 -0
- rtl_buddy/seed_mode.py +7 -0
- rtl_buddy/tools/__init__.py +14 -0
- rtl_buddy/tools/coverage.py +602 -0
- rtl_buddy/tools/coverview.py +764 -0
- rtl_buddy/tools/verible.py +79 -0
- rtl_buddy/tools/verilator_cov_analysis.md +489 -0
- rtl_buddy/tools/vlog_cov.py +1124 -0
- rtl_buddy/tools/vlog_filelist.py +184 -0
- rtl_buddy/tools/vlog_post.py +81 -0
- rtl_buddy/tools/vlog_sim.py +398 -0
- rtl_buddy-2.1.4.dist-info/METADATA +113 -0
- rtl_buddy-2.1.4.dist-info/RECORD +36 -0
- rtl_buddy-2.1.4.dist-info/WHEEL +5 -0
- rtl_buddy-2.1.4.dist-info/entry_points.txt +4 -0
- rtl_buddy-2.1.4.dist-info/licenses/LICENSE +11 -0
- rtl_buddy-2.1.4.dist-info/top_level.txt +1 -0
rtl_buddy/__init__.py
ADDED
rtl_buddy/__main__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# rtl-buddy
|
|
2
|
+
# vim: set sw=2:ts=2:et:
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2024 rtl_buddy contributors
|
|
5
|
+
#
|
|
6
|
+
import logging
|
|
7
|
+
from .rtl_buddy import RtlBuddy
|
|
8
|
+
|
|
9
|
+
DESCRIPTION = """
|
|
10
|
+
RTL Buddy is a RTL development build system.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def main() -> int:
|
|
14
|
+
rb = RtlBuddy(name='rtl_buddy_inst')
|
|
15
|
+
return rb.run()
|
|
16
|
+
|
|
17
|
+
if __name__ == '__main__':
|
|
18
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# rtl-buddy
|
|
2
|
+
# vim: set sw=2:ts=2:et:
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2024 rtl_buddy contributors
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
# Re-export config classes
|
|
8
|
+
from .test import TestConfig, TestbenchConfig
|
|
9
|
+
from .suite import SuiteConfig
|
|
10
|
+
from .reg import RegConfig
|
|
11
|
+
from .root import RootConfig
|
|
12
|
+
from .platform import PlatformConfig
|
|
13
|
+
from .rtl import RtlBuilderConfig
|
|
14
|
+
from .model import ModelConfig, ModelConfigLoader
|
|
15
|
+
from .verible import VeribleConfig
|
|
16
|
+
from .coverage import CoverageConfig, CoverageConfigFile
|
|
17
|
+
from .coverview import CoverviewConfig, CoverviewConfigFile
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import pprint
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from serde import serde, field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class CoverageConfig:
|
|
9
|
+
"""
|
|
10
|
+
Coverage post-processing configuration for a simulator family.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
name (str): Simulator family name, e.g. "verilator" or "vcs".
|
|
14
|
+
use_lcov (bool): Whether LCOV output should be emitted for this simulator.
|
|
15
|
+
"""
|
|
16
|
+
name: str
|
|
17
|
+
use_lcov: bool
|
|
18
|
+
|
|
19
|
+
def get_name(self) -> str:
|
|
20
|
+
return self.name
|
|
21
|
+
|
|
22
|
+
def get_use_lcov(self) -> bool:
|
|
23
|
+
return self.use_lcov
|
|
24
|
+
|
|
25
|
+
def __str__(self):
|
|
26
|
+
return pprint.pformat(self)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@serde
|
|
30
|
+
class CoverageConfigFile:
|
|
31
|
+
"""
|
|
32
|
+
YAML-backed coverage configuration entry.
|
|
33
|
+
"""
|
|
34
|
+
name: str
|
|
35
|
+
use_lcov: bool = field(rename='use-lcov', default=False)
|
|
36
|
+
|
|
37
|
+
def initialise(self) -> CoverageConfig:
|
|
38
|
+
return CoverageConfig(
|
|
39
|
+
name=self.name,
|
|
40
|
+
use_lcov=self.use_lcov,
|
|
41
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import pprint
|
|
2
|
+
from collections.abc import Mapping
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from serde import serde, field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class CoverviewConfig:
|
|
10
|
+
"""
|
|
11
|
+
Coverview packaging configuration for a simulator family.
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
name (str): Simulator family name, e.g. "verilator" or "vcs".
|
|
15
|
+
config (dict): Inline Coverview JSON-compatible configuration values.
|
|
16
|
+
generate_tables (str | None): Optional coverage type to use for Coverview tables.
|
|
17
|
+
"""
|
|
18
|
+
name: str
|
|
19
|
+
config: dict
|
|
20
|
+
generate_tables: str | None
|
|
21
|
+
|
|
22
|
+
def get_name(self) -> str:
|
|
23
|
+
return self.name
|
|
24
|
+
|
|
25
|
+
def get_config(self) -> dict:
|
|
26
|
+
return self.config
|
|
27
|
+
|
|
28
|
+
def get_generate_tables(self) -> str | None:
|
|
29
|
+
return self.generate_tables
|
|
30
|
+
|
|
31
|
+
def __str__(self):
|
|
32
|
+
return pprint.pformat(self)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@serde
|
|
36
|
+
class CoverviewConfigFile:
|
|
37
|
+
"""
|
|
38
|
+
YAML-backed Coverview packaging configuration entry.
|
|
39
|
+
"""
|
|
40
|
+
name: str
|
|
41
|
+
config: dict = field(default_factory=dict)
|
|
42
|
+
generate_tables: str | None = field(rename='generate-tables', default=None)
|
|
43
|
+
|
|
44
|
+
def initialise(self, root_cfg_path: str) -> CoverviewConfig:
|
|
45
|
+
del root_cfg_path
|
|
46
|
+
if not isinstance(self.config, Mapping):
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"cfg-coverview '{self.name}' config must be a mapping of inline Coverview JSON values"
|
|
49
|
+
)
|
|
50
|
+
return CoverviewConfig(
|
|
51
|
+
name=self.name,
|
|
52
|
+
config=dict(self.config),
|
|
53
|
+
generate_tables=self.generate_tables,
|
|
54
|
+
)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
logger = logging.getLogger(__name__)
|
|
3
|
+
import pprint
|
|
4
|
+
|
|
5
|
+
from serde import serde, field
|
|
6
|
+
from serde.yaml import from_yaml
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
from ..errors import FatalRtlBuddyError
|
|
10
|
+
from ..logging_utils import log_event
|
|
11
|
+
|
|
12
|
+
@serde
|
|
13
|
+
class ModelConfig:
|
|
14
|
+
"""
|
|
15
|
+
Representation of a single model entry in a 'model_config' file
|
|
16
|
+
|
|
17
|
+
Attributes
|
|
18
|
+
name (str): Unique model identifier.
|
|
19
|
+
filelist (list[str]): List of paths to files associated with the model.
|
|
20
|
+
path (str|None): Path to the model config file. Will usually be set by the loader.
|
|
21
|
+
"""
|
|
22
|
+
name: str
|
|
23
|
+
filelist: list[str]
|
|
24
|
+
path: str|None
|
|
25
|
+
|
|
26
|
+
def get_model_name(self):
|
|
27
|
+
"""
|
|
28
|
+
Retrieve the value of model_name.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
model_name (str): The value of model_name in the model.
|
|
32
|
+
"""
|
|
33
|
+
return self.model_name
|
|
34
|
+
|
|
35
|
+
def get_model_path(self):
|
|
36
|
+
"""
|
|
37
|
+
Retrieve the value of path.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
path (str): The value of path in the model. The path to the model config file.
|
|
41
|
+
"""
|
|
42
|
+
return self.path
|
|
43
|
+
|
|
44
|
+
def get_filelist(self):
|
|
45
|
+
"""
|
|
46
|
+
Retrieve the value of filelist.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
filelist (list[str]): The value of filelist in the model.
|
|
50
|
+
"""
|
|
51
|
+
return self.filelist
|
|
52
|
+
|
|
53
|
+
def __str__(self):
|
|
54
|
+
return pprint.pformat(self)
|
|
55
|
+
|
|
56
|
+
@serde
|
|
57
|
+
class ModelConfigFile:
|
|
58
|
+
"""
|
|
59
|
+
Representation of a 'model_config' file.
|
|
60
|
+
|
|
61
|
+
Attributes
|
|
62
|
+
rtl_buddy_filetype (Literal['model_config']): Config file type. Must be 'model_config'.
|
|
63
|
+
models (list[RawModelConfig]): List of model configurations.
|
|
64
|
+
"""
|
|
65
|
+
rtl_buddy_filetype: Literal['model_config'] = field(rename='rtl-buddy-filetype')
|
|
66
|
+
models: list[ModelConfig] = field(default_factory=list)
|
|
67
|
+
|
|
68
|
+
# TODO: Raise errors instead of killing things here
|
|
69
|
+
class ModelConfigLoader:
|
|
70
|
+
"""
|
|
71
|
+
Helper class to load model configurations from a file. Reads the file once.
|
|
72
|
+
|
|
73
|
+
Attributes:
|
|
74
|
+
models(list[RawModelConfig]): List of raw model configs.
|
|
75
|
+
"""
|
|
76
|
+
def __init__(self, path:str) -> None:
|
|
77
|
+
self.path = path
|
|
78
|
+
self.models = []
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
with open(self.path, 'r') as file:
|
|
82
|
+
data = from_yaml(ModelConfigFile, file.read())
|
|
83
|
+
self.models = data.models
|
|
84
|
+
except Exception as e:
|
|
85
|
+
log_event(logger, logging.ERROR, "model_config.load_failed", path=path, error=e)
|
|
86
|
+
raise FatalRtlBuddyError(f'failed to load "{path}"') from e
|
|
87
|
+
|
|
88
|
+
def get_model(self, model_name:str) -> ModelConfig:
|
|
89
|
+
"""
|
|
90
|
+
Get a ModelConfig according to model_name.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
name (str): Unique system identifier for the model.
|
|
94
|
+
model_name (str): Unique identifier for the model in file.
|
|
95
|
+
Returns:
|
|
96
|
+
model (ModelConfig): The model configuration.
|
|
97
|
+
Raises:
|
|
98
|
+
Panics if no model corresponding to model_name can be found.
|
|
99
|
+
"""
|
|
100
|
+
for model in self.models:
|
|
101
|
+
if model.name == model_name:
|
|
102
|
+
model.path = self.path
|
|
103
|
+
return model
|
|
104
|
+
|
|
105
|
+
log_event(logger, logging.ERROR, "model_config.model_not_found", model=model_name, path=self.path)
|
|
106
|
+
raise FatalRtlBuddyError(f"model '{model_name}' not found")
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
logger = logging.getLogger(__name__)
|
|
3
|
+
import pprint
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from serde import serde, field
|
|
7
|
+
from .rtl import RtlBuilderConfig
|
|
8
|
+
from .verible import VeribleConfig
|
|
9
|
+
from ..errors import FatalRtlBuddyError
|
|
10
|
+
from ..logging_utils import log_event
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class PlatformConfig:
|
|
14
|
+
"""
|
|
15
|
+
Configuration entry defining a single test platoform.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
os (str): Target OS of platform.
|
|
19
|
+
unames (list[str]): List of supported unames for the platform.
|
|
20
|
+
builder (str | None): Name of builder configuration associated with the platform.
|
|
21
|
+
verible (str): Name of verible configuration associated with the platform.
|
|
22
|
+
"""
|
|
23
|
+
os: str
|
|
24
|
+
unames: list[str]
|
|
25
|
+
builder: RtlBuilderConfig
|
|
26
|
+
verible: VeribleConfig
|
|
27
|
+
|
|
28
|
+
def get_os(self) -> str:
|
|
29
|
+
"""
|
|
30
|
+
Retrieve the value of os.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
os (str): The value of os
|
|
34
|
+
"""
|
|
35
|
+
return self.os
|
|
36
|
+
|
|
37
|
+
def get_builder(self) -> RtlBuilderConfig:
|
|
38
|
+
"""
|
|
39
|
+
Get the value of builder
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
builder (RtlBuilderConfig): The value of builder.
|
|
43
|
+
"""
|
|
44
|
+
return self.builder
|
|
45
|
+
|
|
46
|
+
def get_verible(self) -> VeribleConfig:
|
|
47
|
+
"""
|
|
48
|
+
Get the value of verible.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
verible_name (str): The value of verible.
|
|
52
|
+
"""
|
|
53
|
+
return self.verible
|
|
54
|
+
|
|
55
|
+
def __str__(self) -> str:
|
|
56
|
+
return pprint.pformat(self)
|
|
57
|
+
|
|
58
|
+
@serde
|
|
59
|
+
class PlatformConfigFile:
|
|
60
|
+
os: str
|
|
61
|
+
unames: list[str]
|
|
62
|
+
builder: str | None
|
|
63
|
+
verible: str
|
|
64
|
+
|
|
65
|
+
def initialise(self, builders:dict[str, RtlBuilderConfig], veribles:dict[str, VeribleConfig], builder_override:str|None) -> PlatformConfig:
|
|
66
|
+
builder = None
|
|
67
|
+
if self.builder is not None:
|
|
68
|
+
if self.builder not in builders:
|
|
69
|
+
log_event(logger, logging.ERROR, "platform.builder_missing", builder=self.builder, os=self.os)
|
|
70
|
+
raise FatalRtlBuddyError(f'"{self.builder}" not in root config')
|
|
71
|
+
|
|
72
|
+
builder = builders[self.builder]
|
|
73
|
+
|
|
74
|
+
if builder_override is not None:
|
|
75
|
+
log_event(logger, logging.INFO, "platform.builder_override", builder=builder_override, configured_builder=self.builder, os=self.os)
|
|
76
|
+
if builder_override not in builders:
|
|
77
|
+
log_event(logger, logging.ERROR, "platform.builder_override_missing", builder=builder_override, os=self.os)
|
|
78
|
+
raise FatalRtlBuddyError(f'Builder override "{builder_override}" is not in root config.')
|
|
79
|
+
|
|
80
|
+
builder = builders[builder_override]
|
|
81
|
+
|
|
82
|
+
if builder is None:
|
|
83
|
+
log_event(logger, logging.ERROR, "platform.builder_unset", os=self.os)
|
|
84
|
+
raise FatalRtlBuddyError("Both builder and builder_override are not set. Builder is None")
|
|
85
|
+
|
|
86
|
+
if self.verible not in veribles:
|
|
87
|
+
log_event(logger, logging.ERROR, "platform.verible_missing", verible=self.verible, os=self.os)
|
|
88
|
+
raise FatalRtlBuddyError(f'"{self.verible}" not in verible config')
|
|
89
|
+
|
|
90
|
+
return PlatformConfig(self.os, self.unames, builder, veribles[self.verible])
|
|
91
|
+
|
|
92
|
+
def get_os(self) -> str:
|
|
93
|
+
"""
|
|
94
|
+
Retrieve the value of os.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
os (str): The value of os
|
|
98
|
+
"""
|
|
99
|
+
return self.os
|
|
100
|
+
|
|
101
|
+
def get_unames(self) -> list[str]:
|
|
102
|
+
"""
|
|
103
|
+
Retrieve the value of unames, the list of unames supported by the platform.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
unames (list[str]): The value of unames.
|
|
107
|
+
"""
|
|
108
|
+
return self.unames
|
rtl_buddy/config/reg.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
logger = logging.getLogger(__name__)
|
|
3
|
+
import pprint
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from serde import serde, field, SerdeError
|
|
7
|
+
from serde.yaml import from_yaml
|
|
8
|
+
from typing import Literal
|
|
9
|
+
from .suite import SuiteConfig
|
|
10
|
+
from ..errors import FatalRtlBuddyError
|
|
11
|
+
from ..logging_utils import log_event
|
|
12
|
+
|
|
13
|
+
@serde
|
|
14
|
+
class RegConfigFile:
|
|
15
|
+
"""
|
|
16
|
+
Representation of a "reg_config' file.
|
|
17
|
+
|
|
18
|
+
Attributes
|
|
19
|
+
rtl_buddy_filetype (Literal['reg_config']): Config file type. Must be 'reg_config'.
|
|
20
|
+
test_configs (list[str]): List of paths to test configurations.
|
|
21
|
+
"""
|
|
22
|
+
rtl_buddy_filetype: Literal['reg_config'] = field(rename='rtl-buddy-filetype')
|
|
23
|
+
test_configs: list[str] = field(rename='test-configs', default_factory=list)
|
|
24
|
+
|
|
25
|
+
class RegConfig:
|
|
26
|
+
"""
|
|
27
|
+
Configuration for a set of regression tests.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
name (str): Unique regression test identifier.
|
|
31
|
+
path (str): Path to the regression test file.
|
|
32
|
+
test_configs (list[str]): List of paths to test suite files defining tests in the regression test.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, name:str, path:str) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Initialise a RegConfig given a path to a YAML configuration file.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
name (str): Unique regression test identifier.
|
|
41
|
+
path (str): Path to the regression test configuration file.
|
|
42
|
+
Raises:
|
|
43
|
+
SystemExitError: If there was an error parsing the file.
|
|
44
|
+
"""
|
|
45
|
+
self.name = name
|
|
46
|
+
self.path = path
|
|
47
|
+
self.suite_configs = []
|
|
48
|
+
try:
|
|
49
|
+
with open(path, 'r') as file:
|
|
50
|
+
data = from_yaml(RegConfigFile, file.read())
|
|
51
|
+
self.suite_configs = list(map(lambda suite_path: SuiteConfig(os.path.join(os.path.dirname(self.path), suite_path)), data.test_configs))
|
|
52
|
+
except Exception as e:
|
|
53
|
+
log_event(logger, logging.ERROR, "regression_config.load_failed", name=self.name, path=path, error=e)
|
|
54
|
+
raise FatalRtlBuddyError(f'{self.name}: failed to load "{path}"') from e
|
|
55
|
+
|
|
56
|
+
def get_name(self):
|
|
57
|
+
"""
|
|
58
|
+
Retrieve the value of name
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
name (str): The name of the regression test
|
|
62
|
+
"""
|
|
63
|
+
return self.name
|
|
64
|
+
|
|
65
|
+
def get_path(self):
|
|
66
|
+
"""
|
|
67
|
+
Retrieve the value of path
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
path (str): The value of path in the regression test
|
|
71
|
+
"""
|
|
72
|
+
return self.path
|
|
73
|
+
|
|
74
|
+
def get_suite_configs(self):
|
|
75
|
+
"""
|
|
76
|
+
Retrieve the value of suite_configs
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
test_configs (list[SuiteConfig]): The value of suite_configs in the regression test
|
|
80
|
+
"""
|
|
81
|
+
return self.suite_configs
|
|
82
|
+
|
|
83
|
+
def __str__(self):
|
|
84
|
+
return pprint.pformat(self)
|