socx-cli 0.1.0__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.
- socx_cli-0.1.0.dist-info/METADATA +34 -0
- socx_cli-0.1.0.dist-info/RECORD +41 -0
- socx_cli-0.1.0.dist-info/WHEEL +4 -0
- socx_cli-0.1.0.dist-info/entry_points.txt +2 -0
- socx_cli-0.1.0.dist-info/licenses/LICENSE +201 -0
- src/plugins/config.py +92 -0
- src/plugins/convert/lst.py +12 -0
- src/plugins/example.py +43 -0
- src/plugins/rgr.py +28 -0
- src/socx/__init__.py +132 -0
- src/socx/__main__.py +5 -0
- src/socx/cli.py +169 -0
- src/socx/config/__init__.py +88 -0
- src/socx/config/_config.py +357 -0
- src/socx/console.py +8 -0
- src/socx/converter.py +71 -0
- src/socx/core/__init__.py +2 -0
- src/socx/core/_uid.py +36 -0
- src/socx/core/mixins.py +34 -0
- src/socx/formatter.py +61 -0
- src/socx/log.py +224 -0
- src/socx/memory.py +86 -0
- src/socx/parser.py +153 -0
- src/socx/reader.py +47 -0
- src/socx/regression/__init__.py +14 -0
- src/socx/regression/regression.py +129 -0
- src/socx/regression/test.py +244 -0
- src/socx/static/toml/convert.local.toml +2 -0
- src/socx/static/toml/converter.toml +119 -0
- src/socx/static/toml/filetypes.toml +104 -0
- src/socx/static/toml/plugins.toml +5 -0
- src/socx/static/toml/regression.toml +47 -0
- src/socx/static/toml/settings.toml +6 -0
- src/socx/static/toml/test.toml +9 -0
- src/socx/tokenizer.py +63 -0
- src/socx/validators.py +57 -0
- src/socx/visitor.py +70 -0
- src/socx/writer.py +58 -0
- src/socx-tui/__init__.py +0 -0
- src/socx-tui/app.py +7 -0
- src/socx-tui/regression/table.py +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TextIO
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from subprocess import Popen
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from dynaconf.utils.boxing import DynaBox
|
|
9
|
+
|
|
10
|
+
# from .. import visitor
|
|
11
|
+
from ..config import settings
|
|
12
|
+
from .test import Test
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ("Status", "Regression")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from .test import Status as Status
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(init=False)
|
|
22
|
+
class Regression:
|
|
23
|
+
uid: int
|
|
24
|
+
name: str
|
|
25
|
+
log: Path
|
|
26
|
+
tests: list[Test]
|
|
27
|
+
status: list[Status]
|
|
28
|
+
options: DynaBox
|
|
29
|
+
test_logs: list[Path]
|
|
30
|
+
|
|
31
|
+
def start(self) -> None:
|
|
32
|
+
"""Start a test in a subprocess."""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
def stop(self) -> None:
|
|
36
|
+
"""Send a keyboard interrupt (SIGINT) to stop a running test."""
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
def pause(self) -> None:
|
|
40
|
+
"""Pause the process if it is running."""
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def resume(self) -> None:
|
|
44
|
+
"""Resume the process if it is paused."""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
def wait(self, timeout: float | None = None) -> None:
|
|
48
|
+
"""Wait for a test to terminate if it is running."""
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
def kill(self) -> None:
|
|
52
|
+
"""See `subprocess.Popen.kill`."""
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def export(self, fmt: str = "csv") -> None:
|
|
56
|
+
"""Export regression sessions to the specified format `fmt`."""
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
def terminate(self) -> None:
|
|
60
|
+
"""See `subprocess.Popen.terminate`."""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def log(self) -> Path:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def options(self) -> DynaBox:
|
|
69
|
+
return settings.regression
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def process(self) -> Popen | None:
|
|
73
|
+
"""The active process of the running test or None if not running."""
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def stdin(self) -> TextIO | None:
|
|
78
|
+
"""The standard input of the test's process or None if not running."""
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def stdout(self) -> TextIO | None:
|
|
83
|
+
"""The standard output of the test's process or None if not running."""
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def stderr(self) -> TextIO | None:
|
|
88
|
+
"""The standard error of the test's process or None if not running."""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def status(self) -> Status:
|
|
93
|
+
"""A `TestStatus` representing the state/status of the test."""
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def test_logs(self) -> dict[str, Path]:
|
|
98
|
+
"""Return a mapping between test names and their log paths."""
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def idle(self) -> bool:
|
|
103
|
+
"""True if test has no active process and has not yet started."""
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def passed(self) -> bool:
|
|
108
|
+
"""True if test has finished running and no errors occured."""
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def failed(self) -> bool:
|
|
113
|
+
"""True if test finished running and at least one error occured."""
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def running(self) -> bool:
|
|
118
|
+
"""True if test is currently running in a dedicated process."""
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def finished(self) -> bool:
|
|
123
|
+
"""True if test finished running without normally interruption."""
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def returncode(self) -> int | None:
|
|
128
|
+
"""The return code from the test process or None if running or idle."""
|
|
129
|
+
pass
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import signal
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
from typing import TextIO
|
|
6
|
+
from enum import auto
|
|
7
|
+
from enum import IntEnum
|
|
8
|
+
from subprocess import Popen
|
|
9
|
+
from subprocess import PIPE
|
|
10
|
+
from dataclasses import field
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Status(IntEnum):
|
|
15
|
+
"""
|
|
16
|
+
Status representation of a test process as an `IntEnum`.
|
|
17
|
+
|
|
18
|
+
Members
|
|
19
|
+
-------
|
|
20
|
+
Idle: IntEnum
|
|
21
|
+
Idle state, awaiting to be started.
|
|
22
|
+
|
|
23
|
+
Running: IntEnum
|
|
24
|
+
Test is currently running on a seperate process.
|
|
25
|
+
|
|
26
|
+
Passed: IntEnum
|
|
27
|
+
Test has ended with no errors and a clean exit code.
|
|
28
|
+
|
|
29
|
+
Failed: IntEnum
|
|
30
|
+
Test had failed due to an error or an invalid exit code.
|
|
31
|
+
|
|
32
|
+
Killed: IntEnum
|
|
33
|
+
Test was intentionally killed by a signal.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
Idle = auto(0)
|
|
37
|
+
Running = auto()
|
|
38
|
+
Passed = auto()
|
|
39
|
+
Failed = auto()
|
|
40
|
+
Killed = auto()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class Command:
|
|
45
|
+
"""
|
|
46
|
+
Representation of a 'run test' command-line as an object.
|
|
47
|
+
|
|
48
|
+
Members
|
|
49
|
+
-------
|
|
50
|
+
line: str
|
|
51
|
+
Full commandline string of the command represented by this object.
|
|
52
|
+
|
|
53
|
+
name: str
|
|
54
|
+
Name of the command represented by this object, i.e. sys.argv[0].
|
|
55
|
+
|
|
56
|
+
args: list[str]
|
|
57
|
+
Arguments of the command represented by this object split by
|
|
58
|
+
whitespace.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
name: str = field(init=False)
|
|
62
|
+
args: list[str] = field(init=False)
|
|
63
|
+
line: str
|
|
64
|
+
|
|
65
|
+
def __getattr__(self, attr: str) -> str:
|
|
66
|
+
v = self.extract_argv(f"--{attr}")
|
|
67
|
+
if v:
|
|
68
|
+
return v
|
|
69
|
+
else:
|
|
70
|
+
raise AttributeError
|
|
71
|
+
|
|
72
|
+
def extract_argv(self, arg: str) -> str:
|
|
73
|
+
with suppress(ValueError):
|
|
74
|
+
index = self.args.index(f"{arg}")
|
|
75
|
+
return self.args[index + 1] if index + 1 < len(self.args) else ""
|
|
76
|
+
return ""
|
|
77
|
+
|
|
78
|
+
def __post_init__(self) -> None:
|
|
79
|
+
self.line = self.line.strip()
|
|
80
|
+
self.args = [arg.strip() for arg in self.line.split()]
|
|
81
|
+
self.name = self.args[0] if self.args else ""
|
|
82
|
+
|
|
83
|
+
def __hash__(self) -> int:
|
|
84
|
+
return hash(self.line)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass(init=False)
|
|
88
|
+
class Test:
|
|
89
|
+
"""Representation of a test as a python object."""
|
|
90
|
+
|
|
91
|
+
name: str
|
|
92
|
+
flow: str
|
|
93
|
+
seed: int
|
|
94
|
+
status: Status
|
|
95
|
+
command: Command
|
|
96
|
+
process: Popen | None
|
|
97
|
+
|
|
98
|
+
def __init__(self, command: str | Command) -> None:
|
|
99
|
+
self._proc = None
|
|
100
|
+
self._command = (
|
|
101
|
+
command
|
|
102
|
+
if isinstance(command, Command)
|
|
103
|
+
else Command(command)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def pid(self) -> int | None:
|
|
108
|
+
"""Process id of the test's active process or None if inactive."""
|
|
109
|
+
return self.process.pid if self.process else None
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def name(self) -> str:
|
|
113
|
+
"""The test name or empty string if command does not specify a test."""
|
|
114
|
+
test = self.command.test
|
|
115
|
+
if "/" in test:
|
|
116
|
+
test = test.partition("/")[-1]
|
|
117
|
+
return test
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def flow(self):
|
|
121
|
+
"""The flow specified in the test command."""
|
|
122
|
+
return self.command.flow
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def seed(self):
|
|
126
|
+
"""The test seed."""
|
|
127
|
+
with suppress(AttributeError):
|
|
128
|
+
rv = int(self.command.seed)
|
|
129
|
+
return rv
|
|
130
|
+
return 0
|
|
131
|
+
|
|
132
|
+
def start(self) -> None:
|
|
133
|
+
"""Start a test in a subprocess."""
|
|
134
|
+
if self.idle:
|
|
135
|
+
self._proc = Popen(
|
|
136
|
+
args=self.command.args,
|
|
137
|
+
text=True,
|
|
138
|
+
stdout=PIPE,
|
|
139
|
+
stderr=PIPE,
|
|
140
|
+
shell=True,
|
|
141
|
+
)
|
|
142
|
+
else:
|
|
143
|
+
err = "Test is already running."
|
|
144
|
+
raise OSError(err)
|
|
145
|
+
|
|
146
|
+
def stop(self) -> None:
|
|
147
|
+
"""Send a keyboard interrupt (SIGINT) to stop a running test."""
|
|
148
|
+
if self.running:
|
|
149
|
+
self.process.send_signal(signal.SIGINT)
|
|
150
|
+
|
|
151
|
+
def pause(self) -> None:
|
|
152
|
+
"""Pause the process if it is running."""
|
|
153
|
+
if self.running:
|
|
154
|
+
self.process.send_signal(signal.SIGSTOP)
|
|
155
|
+
|
|
156
|
+
def resume(self) -> None:
|
|
157
|
+
"""Resume the process if it is paused."""
|
|
158
|
+
if self.running:
|
|
159
|
+
self.process.send_signal(signal.SIGCONT)
|
|
160
|
+
|
|
161
|
+
def wait(self, timeout: float | None = None) -> None:
|
|
162
|
+
"""Wait for a test to terminate if it is running."""
|
|
163
|
+
if self.running:
|
|
164
|
+
self.process.wait()
|
|
165
|
+
|
|
166
|
+
def kill(self) -> None:
|
|
167
|
+
"""See `subprocess.Popen.kill`."""
|
|
168
|
+
if self.running:
|
|
169
|
+
self.process.kill()
|
|
170
|
+
|
|
171
|
+
def terminate(self) -> None:
|
|
172
|
+
"""See `subprocess.Popen.terminate`."""
|
|
173
|
+
if self.running:
|
|
174
|
+
self.process.terminate()
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def process(self) -> Popen | None:
|
|
178
|
+
"""The active process of the running test or None if not running."""
|
|
179
|
+
return self._proc
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def stdin(self) -> TextIO | None:
|
|
183
|
+
"""The standard input of the test's process or None if not running."""
|
|
184
|
+
return self.process.stdin if self.process else None
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def stdout(self) -> TextIO | None:
|
|
188
|
+
"""The standard output of the test's process or None if not running."""
|
|
189
|
+
return self.process.stdout if self.process else None
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def stderr(self) -> TextIO | None:
|
|
193
|
+
"""The standard error of the test's process or None if not running."""
|
|
194
|
+
return self.process.stderr if self.process else None
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def status(self) -> Status:
|
|
198
|
+
"""A `TestStatus` representing the state/status of the test."""
|
|
199
|
+
return self._status()
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def command(self) -> Command:
|
|
203
|
+
"""A `TestCommand` represeinting the test's command line invocation."""
|
|
204
|
+
return self._command
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def returncode(self) -> int | None:
|
|
208
|
+
"""The return code from the test process or None if running or idle."""
|
|
209
|
+
return self.process.returncode if self.finished else None
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def idle(self) -> bool:
|
|
213
|
+
"""True if test has no active process and has not yet started."""
|
|
214
|
+
return self.status is Status.Idle
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def passed(self) -> bool:
|
|
218
|
+
"""True if test has finished running and no errors occured."""
|
|
219
|
+
return not self.finished and self.status is Status.Passed
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def failed(self) -> bool:
|
|
223
|
+
"""True if test finished running and at least one error occured."""
|
|
224
|
+
return self.finished and self.status is Status.Failed
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def running(self) -> bool:
|
|
228
|
+
"""True if test is currently running in a dedicated process."""
|
|
229
|
+
return self.process is not None and self.process.poll() is None
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def finished(self) -> bool:
|
|
233
|
+
"""True if test finished running without normally interruption."""
|
|
234
|
+
return self.process is not None and self.process.poll() is not None
|
|
235
|
+
|
|
236
|
+
def _status(self) -> Status:
|
|
237
|
+
if self.process is None:
|
|
238
|
+
return Status.Idle
|
|
239
|
+
elif self.stdout.strip().startswith("PPPP"):
|
|
240
|
+
return Status.Passed
|
|
241
|
+
elif self.stdout.strip().startswith("FFFF"):
|
|
242
|
+
return Status.Running
|
|
243
|
+
else:
|
|
244
|
+
return Status.Failed
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
[convert]
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
[convert.lst]
|
|
5
|
+
|
|
6
|
+
# Argument: type
|
|
7
|
+
#
|
|
8
|
+
# Typename of the convert class for performing the conversion.
|
|
9
|
+
#
|
|
10
|
+
type = "LstParser"
|
|
11
|
+
|
|
12
|
+
# Argument: source
|
|
13
|
+
#
|
|
14
|
+
# source directory from which names and patterns defined in include will
|
|
15
|
+
# be searched.
|
|
16
|
+
#
|
|
17
|
+
source = """
|
|
18
|
+
@path @format {env[WAREA]}/Pixie_ROM_FW/PixieROMApp/TapeOutRelease/PIXIE_E4/PxieParserOut
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# Argument: target
|
|
22
|
+
#
|
|
23
|
+
# target directory to which generated outputs will be written.
|
|
24
|
+
#
|
|
25
|
+
target = """
|
|
26
|
+
@path @format {env[TOP_VERIF]}/scripts/socx/assets/lst/outputs
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Argument: base_addr_map
|
|
30
|
+
#
|
|
31
|
+
# Name of the json adress map file of ROM base addresses.
|
|
32
|
+
#
|
|
33
|
+
base_addr_map = "memLd.json"
|
|
34
|
+
|
|
35
|
+
# Argument: base_addr_base
|
|
36
|
+
#
|
|
37
|
+
# The address value's numeric base (hex/octal/decimal/etc.)
|
|
38
|
+
#
|
|
39
|
+
base_addr_base = 16
|
|
40
|
+
|
|
41
|
+
# Argument: include
|
|
42
|
+
#
|
|
43
|
+
# Specifies file names to include in the convert's list of sources to
|
|
44
|
+
# convert.
|
|
45
|
+
#
|
|
46
|
+
# Values can either be an exact filename, a glob pattern, or a
|
|
47
|
+
# combination of both.
|
|
48
|
+
#
|
|
49
|
+
includes = [ "*.lst", "SPUList.list" ]
|
|
50
|
+
|
|
51
|
+
# Argument: exclude
|
|
52
|
+
#
|
|
53
|
+
# Same as include, but excludes files from the list of sources.
|
|
54
|
+
#
|
|
55
|
+
excludes = []
|
|
56
|
+
|
|
57
|
+
# Argument: mappings
|
|
58
|
+
#
|
|
59
|
+
# Mappings between source file names to target file names.
|
|
60
|
+
#
|
|
61
|
+
# Both source and target can either be an exact file name or a
|
|
62
|
+
# 'match' pattern specified by the character %.
|
|
63
|
+
#
|
|
64
|
+
# A match pattern will simply match the missing part of the target's name with
|
|
65
|
+
# the matching missing part in the source name.
|
|
66
|
+
#
|
|
67
|
+
mappings = [
|
|
68
|
+
{input="%.lst", output="%.svh"},
|
|
69
|
+
{input="%.list", output="%.sv"},
|
|
70
|
+
{input="hwsList.lst", output="pixie_hws_cgs.svh"},
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
# -----------------------------------------------------------------------------
|
|
74
|
+
# Path Options
|
|
75
|
+
# -----------------------------------------------------------------------------
|
|
76
|
+
#
|
|
77
|
+
[convert.lst.options]
|
|
78
|
+
|
|
79
|
+
# Option: collision
|
|
80
|
+
#
|
|
81
|
+
# How name collisions should be handled. In other words, what should the
|
|
82
|
+
# convert do when an older version of the output file already exists
|
|
83
|
+
# in the target directory.
|
|
84
|
+
#
|
|
85
|
+
# Options
|
|
86
|
+
# -------
|
|
87
|
+
# skip:
|
|
88
|
+
# filename collisions will be skipped, and the original file is
|
|
89
|
+
# kept.
|
|
90
|
+
#
|
|
91
|
+
# backup:
|
|
92
|
+
# same as overwrite, but creates a copy of the original file with
|
|
93
|
+
# with a '.backup.<timestamp>' file where <timestamp> is replaced
|
|
94
|
+
# with the date and time of when the back up was created.
|
|
95
|
+
#
|
|
96
|
+
# overwrite:
|
|
97
|
+
# filename collisions are handled by overwriting any existing file
|
|
98
|
+
# with the new one upon name collision.
|
|
99
|
+
#
|
|
100
|
+
collision = "overwrite"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# -------------------------------------------------
|
|
104
|
+
# Uncomment below to add another path configuration
|
|
105
|
+
# -------------------------------------------------
|
|
106
|
+
#
|
|
107
|
+
# [[convert]]
|
|
108
|
+
# source = """
|
|
109
|
+
# """
|
|
110
|
+
# target = """
|
|
111
|
+
# """
|
|
112
|
+
# include = []
|
|
113
|
+
# exclude = []
|
|
114
|
+
# mappings = [{}]
|
|
115
|
+
#
|
|
116
|
+
# [convert.options]
|
|
117
|
+
#
|
|
118
|
+
# ...
|
|
119
|
+
#
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
[lang]
|
|
2
|
+
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# Category: Filetype
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
#
|
|
7
|
+
# An array of language element tables where each table specifies a small
|
|
8
|
+
# subset of language features.
|
|
9
|
+
#
|
|
10
|
+
# Each language is identified by name, and is linked by the configured set of
|
|
11
|
+
# possible filetype extensions.
|
|
12
|
+
#
|
|
13
|
+
[lang.systemverilog]
|
|
14
|
+
name = "systemverilog"
|
|
15
|
+
extensions = [".sv", ".svh"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
# Group: Syntax
|
|
20
|
+
# -----------------------------------------------------------------------------
|
|
21
|
+
#
|
|
22
|
+
# Provides example definitions of various lexical language options
|
|
23
|
+
# supported through configuration.
|
|
24
|
+
#
|
|
25
|
+
[lang.systemverilog.syntax]
|
|
26
|
+
|
|
27
|
+
# Option: filetype.indent
|
|
28
|
+
#
|
|
29
|
+
# 4 or 2, these are your options.
|
|
30
|
+
#
|
|
31
|
+
# It has to be a multiple of 2. always has been. enough with the 3
|
|
32
|
+
# spaces madness.
|
|
33
|
+
#
|
|
34
|
+
# 3 doesnt even make any sense! "meh.. but UVM is so big and it also uses 3
|
|
35
|
+
# spaces and i read online tha.." NOOOOO! Shut up! I dont care!
|
|
36
|
+
#
|
|
37
|
+
# 4 or 2! thse are your only options! from now on the mad 3 people get
|
|
38
|
+
# an angry Exception with a recommendation to see a psychologist.
|
|
39
|
+
#
|
|
40
|
+
indent = 4
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
[lang.systemverilog.syntax.comments]
|
|
44
|
+
|
|
45
|
+
# Option: filetype.syntax.comments.line
|
|
46
|
+
#
|
|
47
|
+
# Line comment tokens
|
|
48
|
+
#
|
|
49
|
+
line = "//"
|
|
50
|
+
|
|
51
|
+
# Option: filetype.syntax.comments.block
|
|
52
|
+
#
|
|
53
|
+
# Block comment token specification.
|
|
54
|
+
#
|
|
55
|
+
# Attributes
|
|
56
|
+
# ----------
|
|
57
|
+
# begin:
|
|
58
|
+
# The token that starts the block comment.
|
|
59
|
+
#
|
|
60
|
+
# end:
|
|
61
|
+
# The token that ends the block comment.
|
|
62
|
+
#
|
|
63
|
+
block = {begin="/*", end="*/"}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
[lang.lst]
|
|
67
|
+
name = "lst"
|
|
68
|
+
extensions = [".lst", ".list"]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
[[lang.lst.tokens]]
|
|
72
|
+
name = 'comment'
|
|
73
|
+
expr = '([#])(?!([A-Z]{2,}))(?P<content>.*)'
|
|
74
|
+
subst = '''@format {this.lang.systemverilog.syntax.comments.line} \g<content>
|
|
75
|
+
'''
|
|
76
|
+
starts_scope = false
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
[[lang.lst.tokens]]
|
|
80
|
+
name = 'group'
|
|
81
|
+
expr = '([#])(?P<mem>NVM|ROM)(\W+)(?P<device>[A-Z]{2,})'
|
|
82
|
+
subst = '''
|
|
83
|
+
covergroup cg__\g<device>_\g<mem>_access;
|
|
84
|
+
|
|
85
|
+
cp__\g<device>_\g<mem>_func: coverpoint { vif.\g<device>_\g<mem>_addr }
|
|
86
|
+
{
|
|
87
|
+
'''
|
|
88
|
+
starts_scope = true
|
|
89
|
+
scope_ender = '''
|
|
90
|
+
bins NoFunc = default;
|
|
91
|
+
}
|
|
92
|
+
endgroup: cg__\g<device>_\g<mem>_access
|
|
93
|
+
|
|
94
|
+
'''
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
[[lang.lst.tokens]]
|
|
98
|
+
name = 'statement'
|
|
99
|
+
expr='0x(?P<addr>[0-9a-fA-F]+)\W+(?P<func>\w+)\W+(?P<len>\d+)(?P<other>.*)'
|
|
100
|
+
subst = '''
|
|
101
|
+
bins \g<func> = { [ (('h\g<addr> - 'h{{ base }}) >> 1) : ((('h\g<addr> - 'h{{base}} + 'd\g<len>) >> 1) - 1) ] };
|
|
102
|
+
'''
|
|
103
|
+
starts_scope = false
|
|
104
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[regression]
|
|
2
|
+
root = "@path @format /space/users/ci_wiliot/vw_e0_nightly_regression/regressions"
|
|
3
|
+
|
|
4
|
+
[regression.user.options]
|
|
5
|
+
test_timeout = 7200
|
|
6
|
+
max_runs_in_parallel = 10
|
|
7
|
+
|
|
8
|
+
[regression.user.options.logs]
|
|
9
|
+
path = "@format {env[RAREA]}/regressions"
|
|
10
|
+
enabled = true
|
|
11
|
+
|
|
12
|
+
[regression.logs]
|
|
13
|
+
path = "@path @format {this.regression.root}/logs"
|
|
14
|
+
prev = "@path @format {this.regression.logs.path}/prev"
|
|
15
|
+
latest = "@path @format {this.regression.logs.path}/latest"
|
|
16
|
+
|
|
17
|
+
[regression.nightly]
|
|
18
|
+
path = "@path @format {this.regression.root}/nightly"
|
|
19
|
+
|
|
20
|
+
[regression.files.socrgr_db]
|
|
21
|
+
name = "socRgrDB.pyclass"
|
|
22
|
+
parent = "@path @format {this.regression.nightly}"
|
|
23
|
+
|
|
24
|
+
[regression.files.rerun_cfg]
|
|
25
|
+
name = "rerun_list.cfg"
|
|
26
|
+
parent = "@path @format {this.regression.logs.latest}"
|
|
27
|
+
|
|
28
|
+
[regression.files.test_summary]
|
|
29
|
+
name = "regression_summary.log"
|
|
30
|
+
parent = "@path @format {this.regression.logs.latest}"
|
|
31
|
+
columns = [
|
|
32
|
+
{name="test_name", index=0, type="path"},
|
|
33
|
+
{name="Iter_num", index=1, type="int"},
|
|
34
|
+
{name="testStaus", index=2, type="str"},
|
|
35
|
+
{name="NumErrors", index=3, type="int"},
|
|
36
|
+
{name="SimTime[ns]", index=4, type="time"},
|
|
37
|
+
{name="seed", index=5, type="int"},
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[regression.files.error_summary]
|
|
41
|
+
name = "errors_summary.log"
|
|
42
|
+
parent = "@path @format {this.regression.logs.latest}"
|
|
43
|
+
|
|
44
|
+
[regression.files.failure_history]
|
|
45
|
+
name = "failed_tests_history.log"
|
|
46
|
+
parent = "@path @format {this.regression.logs.latest}"
|
|
47
|
+
|