dvsim 1.7.1__py3-none-any.whl → 1.7.3__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.
dvsim/cli/admin.py CHANGED
@@ -35,9 +35,9 @@ def report() -> None:
35
35
  )
36
36
  def gen(json_path: Path, output_dir: Path) -> None:
37
37
  """Generate a report from a existing results JSON."""
38
- from dvsim.report.data import ResultsSummary
39
- from dvsim.report.generate import gen_reports
38
+ from dvsim.sim.data import SimResultsSummary
39
+ from dvsim.sim.report import gen_reports
40
40
 
41
- results: ResultsSummary = ResultsSummary.load(path=json_path)
41
+ results: SimResultsSummary = SimResultsSummary.load(path=json_path)
42
42
 
43
43
  gen_reports(summary=results, path=output_dir)
dvsim/flow/base.py CHANGED
@@ -10,7 +10,6 @@ import pprint
10
10
  import sys
11
11
  from abc import ABC, abstractmethod
12
12
  from collections.abc import Mapping, Sequence
13
- from datetime import datetime, timezone
14
13
  from pathlib import Path
15
14
  from typing import TYPE_CHECKING, ClassVar
16
15
 
@@ -20,15 +19,12 @@ from dvsim.flow.hjson import set_target_attribute
20
19
  from dvsim.job.data import CompletedJobStatus
21
20
  from dvsim.launcher.factory import get_launcher_cls
22
21
  from dvsim.logging import log
23
- from dvsim.report.data import FlowResults, IPMeta, ResultsSummary
24
- from dvsim.report.generate import gen_block_report, gen_reports
25
22
  from dvsim.scheduler import Scheduler
26
23
  from dvsim.utils import (
27
24
  find_and_substitute_wildcards,
28
25
  rm_path,
29
26
  subst_wildcards,
30
27
  )
31
- from dvsim.utils.git import git_commit_hash
32
28
 
33
29
  if TYPE_CHECKING:
34
30
  from dvsim.job.deploy import Deploy
@@ -447,6 +443,7 @@ class FlowCfg(ABC):
447
443
  interactive=self.interactive,
448
444
  ).run()
449
445
 
446
+ @abstractmethod
450
447
  def gen_results(self, results: Sequence[CompletedJobStatus]) -> None:
451
448
  """Generate flow results.
452
449
 
@@ -454,68 +451,6 @@ class FlowCfg(ABC):
454
451
  results: completed job status objects.
455
452
 
456
453
  """
457
- reports_dir = Path(self.scratch_base_path) / "reports"
458
- commit = git_commit_hash(path=Path(self.proj_root))
459
- url = f"https://github.com/lowrisc/opentitan/tree/{commit}"
460
-
461
- all_flow_results: Mapping[str, FlowResults] = {}
462
-
463
- for item in self.cfgs:
464
- item_results = [
465
- res
466
- for res in results
467
- if res.block.name == item.name and res.block.variant == item.variant
468
- ]
469
-
470
- flow_results: FlowResults = item._gen_json_results(
471
- run_results=item_results,
472
- commit=commit,
473
- url=url,
474
- )
475
-
476
- # Convert to lowercase to match filename
477
- block_result_index = (
478
- f"{item.name}_{item.variant}" if item.variant else item.name
479
- ).lower()
480
-
481
- all_flow_results[block_result_index] = flow_results
482
-
483
- # Generate the block's JSON/HTML reports to the report area.
484
- gen_block_report(
485
- results=flow_results,
486
- path=reports_dir,
487
- )
488
-
489
- self.errors_seen |= item.errors_seen
490
-
491
- if self.is_primary_cfg:
492
- # The timestamp for this run has been taken with `utcnow()` and is
493
- # stored in a custom format. Store it in standard ISO format with
494
- # explicit timezone annotation.
495
- timestamp = (
496
- datetime.strptime(self.timestamp, "%Y%m%d_%H%M%S")
497
- .replace(tzinfo=timezone.utc)
498
- .isoformat()
499
- )
500
-
501
- results_summary = ResultsSummary(
502
- top=IPMeta(
503
- name=self.name,
504
- variant=self.variant,
505
- commit=commit,
506
- branch=self.branch,
507
- url=url,
508
- ),
509
- timestamp=timestamp,
510
- flow_results=all_flow_results,
511
- report_path=reports_dir,
512
- )
513
-
514
- # Generate all the JSON/HTML reports to the report area.
515
- gen_reports(
516
- summary=results_summary,
517
- path=reports_dir,
518
- )
519
454
 
520
455
  def has_errors(self) -> bool:
521
456
  """Return error state."""
dvsim/flow/factory.py CHANGED
@@ -11,9 +11,9 @@ from dvsim.flow.formal import FormalCfg
11
11
  from dvsim.flow.hjson import load_hjson
12
12
  from dvsim.flow.lint import LintCfg
13
13
  from dvsim.flow.rdc import RdcCfg
14
- from dvsim.flow.sim import SimCfg
15
14
  from dvsim.flow.syn import SynCfg
16
15
  from dvsim.logging import log
16
+ from dvsim.sim.flow import SimCfg
17
17
 
18
18
  FLOW_HANDLERS = {
19
19
  "cdc": CdcCfg,
dvsim/flow/formal.py CHANGED
@@ -2,12 +2,14 @@
2
2
  # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ from collections.abc import Sequence
5
6
  from pathlib import Path
6
7
 
7
8
  import hjson
8
9
  from tabulate import tabulate
9
10
 
10
11
  from dvsim.flow.one_shot import OneShotCfg
12
+ from dvsim.job.data import CompletedJobStatus
11
13
  from dvsim.logging import log
12
14
  from dvsim.utils import subst_wildcards
13
15
 
@@ -176,41 +178,47 @@ class FormalCfg(OneShotCfg):
176
178
 
177
179
  return self.results_summary_md
178
180
 
179
- def _gen_results(self, results):
180
- # This function is called after the regression and looks for
181
- # results.hjson file with aggregated results from the formal logfile.
182
- # The hjson file is required to follow this format:
183
- # {
184
- # "messages": {
185
- # "errors" : []
186
- # "warnings" : []
187
- # "cex" : ["property1", "property2"...],
188
- # "undetermined": [],
189
- # "unreachable" : [],
190
- # },
191
- #
192
- # "summary": {
193
- # "errors" : 0
194
- # "warnings" : 2
195
- # "proven" : 20,
196
- # "cex" : 5,
197
- # "covered" : 18,
198
- # "undetermined": 7,
199
- # "unreachable" : 2,
200
- # "pass_rate" : "90 %",
201
- # "cover_rate" : "90 %"
202
- # },
203
- # }
204
- # The categories for property results are: proven, cex, undetermined,
205
- # covered, and unreachable.
206
- #
207
- # If coverage was enabled then results.hjson will also have an item that
208
- # shows formal coverage. It will have the following format:
209
- # "coverage": {
210
- # formal: "90 %",
211
- # stimuli: "90 %",
212
- # checker: "80 %"
213
- # }
181
+ def _gen_results(self, results: Sequence[CompletedJobStatus]) -> None:
182
+ """Generate results.
183
+
184
+ This function is called after the regression and looks for
185
+ results.hjson file with aggregated results from the formal logfile.
186
+ The hjson file is required to follow this format:
187
+ {
188
+ "messages": {
189
+ "errors" : []
190
+ "warnings" : []
191
+ "cex" : ["property1", "property2"...],
192
+ "undetermined": [],
193
+ "unreachable" : [],
194
+ },
195
+
196
+ "summary": {
197
+ "errors" : 0
198
+ "warnings" : 2
199
+ "proven" : 20,
200
+ "cex" : 5,
201
+ "covered" : 18,
202
+ "undetermined": 7,
203
+ "unreachable" : 2,
204
+ "pass_rate" : "90 %",
205
+ "cover_rate" : "90 %"
206
+ },
207
+ }
208
+ The categories for property results are: proven, cex, undetermined,
209
+ covered, and unreachable.
210
+
211
+ If coverage was enabled then results.hjson will also have an item that
212
+ shows formal coverage. It will have the following format:
213
+ "coverage": {
214
+ formal: "90 %",
215
+ stimuli: "90 %",
216
+ checker: "80 %"
217
+ }
218
+ """
219
+ # There should be just one job that has run for this config.
220
+ complete_job = results[0]
221
+
214
222
  results_str = "## " + self.results_title + "\n\n"
215
223
  results_str += "### " + self.timestamp_long + "\n"
216
224
  if self.revision:
@@ -222,7 +230,7 @@ class FormalCfg(OneShotCfg):
222
230
  assert len(self.deploy) == 1
223
231
  mode = self.deploy[0]
224
232
 
225
- if results[mode] == "P":
233
+ if complete_job.status == "P":
226
234
  result_data = Path(
227
235
  subst_wildcards(self.build_dir, {"build_mode": mode.name}),
228
236
  "results.hjson",
@@ -254,8 +262,8 @@ class FormalCfg(OneShotCfg):
254
262
  else:
255
263
  summary += ["N/A", "N/A", "N/A"]
256
264
 
257
- if results[mode] != "P":
258
- results_str += "\n## List of Failures\n" + "".join(mode.launcher.fail_msg.message)
265
+ if complete_job.status != "P":
266
+ results_str += "\n## List of Failures\n" + "".join(complete_job.fail_msg.message)
259
267
 
260
268
  messages = self.result.get("messages")
261
269
  if messages is not None:
dvsim/flow/lint.py CHANGED
@@ -4,11 +4,13 @@
4
4
 
5
5
  """Class describing lint configuration object."""
6
6
 
7
+ from collections.abc import Sequence
7
8
  from pathlib import Path
8
9
 
9
10
  from tabulate import tabulate
10
11
 
11
12
  from dvsim.flow.one_shot import OneShotCfg
13
+ from dvsim.job.data import CompletedJobStatus
12
14
  from dvsim.logging import log
13
15
  from dvsim.msg_buckets import MsgBuckets
14
16
  from dvsim.utils import check_bool, subst_wildcards
@@ -76,7 +78,10 @@ class LintCfg(OneShotCfg):
76
78
 
77
79
  keys = self.totals.get_keys(self.report_severities)
78
80
  for cfg in self.cfgs:
79
- name_with_link = cfg._get_results_page_link(self.results_dir)
81
+ link_text = self.name.upper()
82
+ relative_link = Path(self.results_dir) / self.results_page
83
+
84
+ name_with_link = f"[{link_text}]({relative_link})"
80
85
 
81
86
  row = [name_with_link]
82
87
  row += cfg.result_summary.get_counts_md(keys)
@@ -96,26 +101,26 @@ class LintCfg(OneShotCfg):
96
101
 
97
102
  # TODO(#9079): This way of parsing out messages into an intermediate
98
103
  # results.hjson file will be replaced by a native parser mechanism.
99
- def _gen_results(self, results):
100
- # '''
101
- # The function is called after the regression has completed. It looks
102
- # for a results.hjson file with aggregated results from the lint run.
103
- # The hjson needs to have the following format:
104
- #
105
- # {
106
- # bucket_key: [str],
107
- # // other buckets according to message_buckets configuration
108
- # }
109
- #
110
- # Each bucket key points to a list of signatures (strings).
111
- # The bucket categories and severities are defined in the
112
- # message_buckets class variable, and can be set via Hjson Dvsim
113
- # config files.
114
- #
115
- # Note that if this is a primary config, the results will
116
- # be generated using the _gen_results_summary function
117
- # '''
118
-
104
+ def _gen_results(self, results: Sequence[CompletedJobStatus]) -> None:
105
+ """Generate results.
106
+
107
+ The function is called after the regression has completed. It looks
108
+ for a results.hjson file with aggregated results from the lint run.
109
+ The hjson needs to have the following format:
110
+
111
+ {
112
+ bucket_key: [str],
113
+ // other buckets according to message_buckets configuration
114
+ }
115
+
116
+ Each bucket key points to a list of signatures (strings).
117
+ The bucket categories and severities are defined in the
118
+ message_buckets class variable, and can be set via Hjson Dvsim
119
+ config files.
120
+
121
+ Note that if this is a primary config, the results will
122
+ be generated using the _gen_results_summary function
123
+ """
119
124
  # Generate results table for runs.
120
125
  results_str = f"## {self.results_title}\n\n"
121
126
  results_str += f"### {self.timestamp_long}\n"
dvsim/flow/one_shot.py CHANGED
@@ -4,10 +4,13 @@
4
4
 
5
5
  """Class describing a one-shot build configuration object."""
6
6
 
7
- import pathlib
7
+ from abc import abstractmethod
8
8
  from collections import OrderedDict
9
+ from collections.abc import Sequence
10
+ from pathlib import Path
9
11
 
10
12
  from dvsim.flow.base import FlowCfg
13
+ from dvsim.job.data import CompletedJobStatus
11
14
  from dvsim.job.deploy import CompileOneShot
12
15
  from dvsim.logging import log
13
16
  from dvsim.modes import BuildMode, Mode
@@ -15,9 +18,7 @@ from dvsim.utils import rm_path
15
18
 
16
19
 
17
20
  class OneShotCfg(FlowCfg):
18
- """Simple one-shot build flow for non-simulation targets like
19
- linting, synthesis and FPV.
20
- """
21
+ """Simple one-shot build flow for non-simulation targets like linting, synthesis and FPV."""
21
22
 
22
23
  ignored_wildcards = [*FlowCfg.ignored_wildcards, "build_mode", "index", "test"]
23
24
 
@@ -134,8 +135,10 @@ class OneShotCfg(FlowCfg):
134
135
  def _create_dirs(self) -> None:
135
136
  """Create initial set of directories."""
136
137
  for link in self.links:
137
- rm_path(self.links[link])
138
- pathlib.Path(self.links[link]).mkdir(parents=True)
138
+ link_path = Path(self.links[link])
139
+
140
+ rm_path(link_path)
141
+ link_path.mkdir(parents=True)
139
142
 
140
143
  def _create_deploy_objects(self) -> None:
141
144
  """Create deploy objects from build modes."""
@@ -149,3 +152,49 @@ class OneShotCfg(FlowCfg):
149
152
 
150
153
  # Create initial set of directories before kicking off the regression.
151
154
  self._create_dirs()
155
+
156
+ @abstractmethod
157
+ def _gen_results(self, results: Sequence[CompletedJobStatus]) -> None:
158
+ """Generate results for this config."""
159
+
160
+ @abstractmethod
161
+ def gen_results_summary(self):
162
+ """Gathers the aggregated results from all sub configs."""
163
+
164
+ def gen_results(self, results: Sequence[CompletedJobStatus]) -> None:
165
+ """Generate flow results.
166
+
167
+ Args:
168
+ results: completed job status objects.
169
+
170
+ """
171
+ for item in self.cfgs:
172
+ project = item.name
173
+
174
+ item_results = [
175
+ res
176
+ for res in results
177
+ if res.block.name == item.name and res.block.variant == item.variant
178
+ ]
179
+
180
+ result = item._gen_results(item_results)
181
+
182
+ log.info("[results]: [%s]:\n%s\n", project, result)
183
+ log.info("[scratch_path]: [%s] [%s]", project, item.scratch_path)
184
+
185
+ # TODO: Implement HTML report using templates
186
+
187
+ results_dir = Path(self.results_dir)
188
+ results_dir.mkdir(exist_ok=True, parents=True)
189
+
190
+ # (results_dir / self.results_html_name).write_text(
191
+ # md_results_to_html(self.results_title, self.css_file, item.results_md)
192
+ # )
193
+
194
+ log.verbose("[report]: [%s] [%s/report.html]", project, item.results_dir)
195
+
196
+ self.errors_seen |= item.errors_seen
197
+
198
+ if self.is_primary_cfg:
199
+ self.gen_results_summary()
200
+ # self.write_results(self.results_html_name, self.results_summary_md)
dvsim/job/deploy.py CHANGED
@@ -74,6 +74,10 @@ class Deploy:
74
74
  # Cross ref the whole cfg object for ease.
75
75
  self.sim_cfg = sim_cfg
76
76
  self.flow = sim_cfg.name
77
+
78
+ if not hasattr(self.sim_cfg, "variant"):
79
+ self.sim_cfg.variant = ""
80
+
77
81
  self._variant_suffix = f"_{self.sim_cfg.variant}" if self.sim_cfg.variant else ""
78
82
 
79
83
  # A list of jobs on which this job depends.
dvsim/launcher/base.py CHANGED
@@ -339,25 +339,28 @@ class Launcher(ABC):
339
339
  # since it is devoid of the delays incurred due to infrastructure and
340
340
  # setup overhead.
341
341
 
342
- plugin = get_sim_tool_plugin(tool=self.job_spec.tool.name)
342
+ time = self.job_runtime_secs
343
+ unit = "s"
344
+
345
+ if self.job_spec.job_type in [
346
+ "CompileSim",
347
+ "RunTest",
348
+ "CovUnr",
349
+ "CovMerge",
350
+ "CovReport",
351
+ "CovAnalyze",
352
+ ]:
353
+ plugin = get_sim_tool_plugin(tool=self.job_spec.tool.name)
343
354
 
344
- try:
345
- time, unit = plugin.get_job_runtime(log_text=lines)
346
- self.job_runtime.set(time, unit)
347
-
348
- except RuntimeError as e:
349
- log.warning(
350
- f"{self.job_spec.full_name}: {e} Using dvsim-maintained job_runtime instead."
351
- )
352
- self.job_runtime.set(self.job_runtime_secs, "s")
353
-
354
- if self.job_spec.job_type == "RunTest":
355
355
  try:
356
- time, unit = plugin.get_simulated_time(log_text=lines)
357
- self.simulated_time.set(time, unit)
356
+ time, unit = plugin.get_job_runtime(log_text=lines)
358
357
 
359
358
  except RuntimeError as e:
360
- log.debug(f"{self.job_spec.full_name}: {e}")
359
+ log.warning(
360
+ f"{self.job_spec.full_name}: {e} Using dvsim-maintained job_runtime instead."
361
+ )
362
+
363
+ self.job_runtime.set(time, unit)
361
364
 
362
365
  if chk_failed or chk_passed:
363
366
  for cnt, line in enumerate(lines):
dvsim/report/data.py CHANGED
@@ -4,17 +4,11 @@
4
4
 
5
5
  """Report data models."""
6
6
 
7
- from collections.abc import Mapping
8
- from datetime import datetime
9
- from pathlib import Path
10
-
11
7
  from pydantic import BaseModel, ConfigDict
12
8
 
13
- from dvsim.sim_results import BucketedFailures
14
-
15
9
  __all__ = (
16
10
  "IPMeta",
17
- "ResultsSummary",
11
+ "ToolMeta",
18
12
  )
19
13
 
20
14
 
@@ -45,197 +39,3 @@ class ToolMeta(BaseModel):
45
39
  """Name of the tool."""
46
40
  version: str
47
41
  """Version of the tool."""
48
-
49
-
50
- class TestResult(BaseModel):
51
- """Test result."""
52
-
53
- model_config = ConfigDict(frozen=True, extra="forbid")
54
-
55
- max_time: float
56
- """Run time."""
57
- sim_time: float
58
- """Simulation time."""
59
-
60
- passed: int
61
- """Number of tests passed."""
62
- total: int
63
- """Total number of tests run."""
64
- percent: float
65
- """Percentage test pass rate."""
66
-
67
-
68
- class Testpoint(BaseModel):
69
- """Testpoint."""
70
-
71
- model_config = ConfigDict(frozen=True, extra="forbid")
72
-
73
- tests: Mapping[str, TestResult]
74
- """Test results."""
75
-
76
- passed: int
77
- """Number of tests passed."""
78
- total: int
79
- """Total number of tests run."""
80
- percent: float
81
- """Percentage test pass rate."""
82
-
83
-
84
- class TestStage(BaseModel):
85
- """Test stages."""
86
-
87
- model_config = ConfigDict(frozen=True, extra="forbid")
88
-
89
- testpoints: Mapping[str, Testpoint]
90
- """Results by test point."""
91
-
92
- passed: int
93
- """Number of tests passed."""
94
- total: int
95
- """Total number of tests run."""
96
- percent: float
97
- """Percentage test pass rate."""
98
-
99
-
100
- class CodeCoverageMetrics(BaseModel):
101
- """CodeCoverage metrics."""
102
-
103
- model_config = ConfigDict(frozen=True, extra="forbid")
104
-
105
- block: float | None
106
- """Block Coverage (%) - did this part of the code execute?"""
107
- line_statement: float | None
108
- """Line/Statement Coverage (%) - did this part of the code execute?"""
109
- branch: float | None
110
- """Branch Coverage (%) - did this if/case take all paths?"""
111
- condition_expression: float | None
112
- """Condition/Expression Coverage (%) - did the logic evaluate to 0 & 1?"""
113
- toggle: float | None
114
- """Toggle Coverage (%) - did the signal wiggle?"""
115
- fsm: float | None
116
- """FSM Coverage (%) - did the state machine transition?"""
117
-
118
- @property
119
- def average(self) -> float | None:
120
- """Average code coverage (%)."""
121
- all_cov = [
122
- c
123
- for c in [
124
- self.line_statement,
125
- self.branch,
126
- self.condition_expression,
127
- self.toggle,
128
- self.fsm,
129
- ]
130
- if c is not None
131
- ]
132
-
133
- if len(all_cov) == 0:
134
- return None
135
-
136
- return sum(all_cov) / len(all_cov)
137
-
138
-
139
- class CoverageMetrics(BaseModel):
140
- """Coverage metrics."""
141
-
142
- code: CodeCoverageMetrics | None
143
- """Code Coverage."""
144
- assertion: float | None
145
- """Assertion Coverage."""
146
- functional: float | None
147
- """Functional coverage."""
148
-
149
- @property
150
- def average(self) -> float | None:
151
- """Average code coverage (%) or None if there is no coverage."""
152
- code = self.code.average if self.code is not None else None
153
- all_cov = [
154
- c
155
- for c in [
156
- code,
157
- self.assertion,
158
- self.functional,
159
- ]
160
- if c is not None
161
- ]
162
-
163
- if len(all_cov) == 0:
164
- return None
165
-
166
- return sum(all_cov) / len(all_cov)
167
-
168
-
169
- class FlowResults(BaseModel):
170
- """Flow results data."""
171
-
172
- model_config = ConfigDict(frozen=True, extra="forbid")
173
-
174
- block: IPMeta
175
- """IP block metadata."""
176
- tool: ToolMeta
177
- """Tool used in the simulation run."""
178
- timestamp: datetime
179
- """Timestamp for when the test ran."""
180
-
181
- stages: Mapping[str, TestStage]
182
- """Results per test stage."""
183
- coverage: CoverageMetrics | None
184
- """Coverage metrics."""
185
-
186
- failed_jobs: BucketedFailures
187
- """Bucketed failed job overview."""
188
-
189
- passed: int
190
- """Number of tests passed."""
191
- total: int
192
- """Total number of tests run."""
193
- percent: float
194
- """Percentage test pass rate."""
195
-
196
- @staticmethod
197
- def load(path: Path) -> "FlowResults":
198
- """Load results from JSON file.
199
-
200
- Transform the fields of the loaded JSON into a more useful schema for
201
- report generation.
202
-
203
- Args:
204
- path: to the json file to load.
205
-
206
- """
207
- return FlowResults.model_validate_json(path.read_text())
208
-
209
-
210
- class ResultsSummary(BaseModel):
211
- """Summary of results."""
212
-
213
- model_config = ConfigDict(frozen=True, extra="forbid")
214
-
215
- top: IPMeta
216
- """Meta data for the top level config."""
217
-
218
- timestamp: datetime
219
- """Run time stamp."""
220
-
221
- flow_results: Mapping[str, FlowResults]
222
- """Flow results."""
223
-
224
- report_path: Path
225
- """Path to the report JSON file."""
226
-
227
- @staticmethod
228
- def load(path: Path) -> "ResultsSummary":
229
- """Load results from JSON file.
230
-
231
- Transform the fields of the loaded JSON into a more useful schema for
232
- report generation.
233
-
234
- Args:
235
- path: to the json file to load.
236
-
237
- Returns:
238
- The loaded ResultsSummary from JSON.
239
-
240
- """
241
- return ResultsSummary.model_validate_json(path.read_text())
dvsim/sim/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ # Copyright lowRISC contributors (OpenTitan project).
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Simulation workflow."""
dvsim/sim/data.py ADDED
@@ -0,0 +1,259 @@
1
+ # Copyright lowRISC contributors (OpenTitan project).
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Simulation data models."""
6
+
7
+ from collections.abc import Mapping
8
+ from datetime import datetime
9
+ from pathlib import Path
10
+
11
+ from pydantic import BaseModel, ConfigDict
12
+
13
+ from dvsim.report.data import IPMeta, ToolMeta
14
+ from dvsim.sim_results import BucketedFailures
15
+
16
+ __all__ = (
17
+ "CodeCoverageMetrics",
18
+ "CoverageMetrics",
19
+ "SimFlowResults",
20
+ "SimResultsSummary",
21
+ "TestResult",
22
+ "TestStage",
23
+ "Testpoint",
24
+ )
25
+
26
+
27
+ class TestResult(BaseModel):
28
+ """Test result."""
29
+
30
+ model_config = ConfigDict(frozen=True, extra="forbid")
31
+
32
+ max_time: float
33
+ """Run time."""
34
+ sim_time: float
35
+ """Simulation time."""
36
+
37
+ passed: int
38
+ """Number of tests passed."""
39
+ total: int
40
+ """Total number of tests run."""
41
+ percent: float
42
+ """Percentage test pass rate."""
43
+
44
+
45
+ class Testpoint(BaseModel):
46
+ """Testpoint."""
47
+
48
+ model_config = ConfigDict(frozen=True, extra="forbid")
49
+
50
+ tests: Mapping[str, TestResult]
51
+ """Test results."""
52
+
53
+ passed: int
54
+ """Number of tests passed."""
55
+ total: int
56
+ """Total number of tests run."""
57
+ percent: float
58
+ """Percentage test pass rate."""
59
+
60
+
61
+ class TestStage(BaseModel):
62
+ """Test stages."""
63
+
64
+ model_config = ConfigDict(frozen=True, extra="forbid")
65
+
66
+ testpoints: Mapping[str, Testpoint]
67
+ """Results by test point."""
68
+
69
+ passed: int
70
+ """Number of tests passed."""
71
+ total: int
72
+ """Total number of tests run."""
73
+ percent: float
74
+ """Percentage test pass rate."""
75
+
76
+
77
+ class CodeCoverageMetrics(BaseModel):
78
+ """CodeCoverage metrics."""
79
+
80
+ model_config = ConfigDict(frozen=True, extra="forbid")
81
+
82
+ block: float | None
83
+ """Block Coverage (%) - did this part of the code execute?"""
84
+ line_statement: float | None
85
+ """Line/Statement Coverage (%) - did this part of the code execute?"""
86
+ branch: float | None
87
+ """Branch Coverage (%) - did this if/case take all paths?"""
88
+ condition_expression: float | None
89
+ """Condition/Expression Coverage (%) - did the logic evaluate to 0 & 1?"""
90
+ toggle: float | None
91
+ """Toggle Coverage (%) - did the signal wiggle?"""
92
+ fsm: float | None
93
+ """FSM Coverage (%) - did the state machine transition?"""
94
+
95
+ @property
96
+ def average(self) -> float | None:
97
+ """Average code coverage (%)."""
98
+ all_cov = [
99
+ c
100
+ for c in [
101
+ self.line_statement,
102
+ self.branch,
103
+ self.condition_expression,
104
+ self.toggle,
105
+ self.fsm,
106
+ ]
107
+ if c is not None
108
+ ]
109
+
110
+ if len(all_cov) == 0:
111
+ return None
112
+
113
+ return sum(all_cov) / len(all_cov)
114
+
115
+
116
+ class CoverageMetrics(BaseModel):
117
+ """Coverage metrics."""
118
+
119
+ code: CodeCoverageMetrics | None
120
+ """Code Coverage."""
121
+ assertion: float | None
122
+ """Assertion Coverage."""
123
+ functional: float | None
124
+ """Functional coverage."""
125
+
126
+ @property
127
+ def average(self) -> float | None:
128
+ """Average code coverage (%) or None if there is no coverage."""
129
+ code = self.code.average if self.code is not None else None
130
+ all_cov = [
131
+ c
132
+ for c in [
133
+ code,
134
+ self.assertion,
135
+ self.functional,
136
+ ]
137
+ if c is not None
138
+ ]
139
+
140
+ if len(all_cov) == 0:
141
+ return None
142
+
143
+ return sum(all_cov) / len(all_cov)
144
+
145
+
146
+ class FlowResults(BaseModel):
147
+ """Flow results data."""
148
+
149
+ model_config = ConfigDict(frozen=True, extra="forbid")
150
+
151
+ block: IPMeta
152
+ """IP block metadata."""
153
+ tool: ToolMeta
154
+ """Tool used in the simulation run."""
155
+ timestamp: datetime
156
+ """Timestamp for when the test ran."""
157
+
158
+ stages: Mapping[str, TestStage]
159
+ """Results per test stage."""
160
+ coverage: CoverageMetrics | None
161
+ """Coverage metrics."""
162
+
163
+ failed_jobs: BucketedFailures
164
+ """Bucketed failed job overview."""
165
+
166
+ passed: int
167
+ """Number of tests passed."""
168
+ total: int
169
+ """Total number of tests run."""
170
+ percent: float
171
+ """Percentage test pass rate."""
172
+
173
+ @staticmethod
174
+ def load(path: Path) -> "FlowResults":
175
+ """Load results from JSON file.
176
+
177
+ Transform the fields of the loaded JSON into a more useful schema for
178
+ report generation.
179
+
180
+ Args:
181
+ path: to the json file to load.
182
+
183
+ """
184
+ return FlowResults.model_validate_json(path.read_text())
185
+
186
+
187
+ class SimFlowResults(BaseModel):
188
+ """Flow results data."""
189
+
190
+ model_config = ConfigDict(frozen=True, extra="forbid")
191
+
192
+ block: IPMeta
193
+ """IP block metadata."""
194
+ tool: ToolMeta
195
+ """Tool used in the simulation run."""
196
+ timestamp: datetime
197
+ """Timestamp for when the test ran."""
198
+
199
+ stages: Mapping[str, TestStage]
200
+ """Results per test stage."""
201
+ coverage: CoverageMetrics | None
202
+ """Coverage metrics."""
203
+
204
+ failed_jobs: BucketedFailures
205
+ """Bucketed failed job overview."""
206
+
207
+ passed: int
208
+ """Number of tests passed."""
209
+ total: int
210
+ """Total number of tests run."""
211
+ percent: float
212
+ """Percentage test pass rate."""
213
+
214
+ @staticmethod
215
+ def load(path: Path) -> "FlowResults":
216
+ """Load results from JSON file.
217
+
218
+ Transform the fields of the loaded JSON into a more useful schema for
219
+ report generation.
220
+
221
+ Args:
222
+ path: to the json file to load.
223
+
224
+ """
225
+ return FlowResults.model_validate_json(path.read_text())
226
+
227
+
228
+ class SimResultsSummary(BaseModel):
229
+ """Summary of results."""
230
+
231
+ model_config = ConfigDict(frozen=True, extra="forbid")
232
+
233
+ top: IPMeta
234
+ """Meta data for the top level config."""
235
+
236
+ timestamp: datetime
237
+ """Run time stamp."""
238
+
239
+ flow_results: Mapping[str, SimFlowResults]
240
+ """Flow results."""
241
+
242
+ report_path: Path
243
+ """Path to the report JSON file."""
244
+
245
+ @staticmethod
246
+ def load(path: Path) -> "SimResultsSummary":
247
+ """Load results from JSON file.
248
+
249
+ Transform the fields of the loaded JSON into a more useful schema for
250
+ report generation.
251
+
252
+ Args:
253
+ path: to the json file to load.
254
+
255
+ Returns:
256
+ The loaded ResultsSummary from JSON.
257
+
258
+ """
259
+ return SimResultsSummary.model_validate_json(path.read_text())
@@ -7,7 +7,7 @@
7
7
  import fnmatch
8
8
  import sys
9
9
  from collections import OrderedDict, defaultdict
10
- from collections.abc import Sequence
10
+ from collections.abc import Mapping, Sequence
11
11
  from datetime import datetime, timezone
12
12
  from pathlib import Path
13
13
  from typing import ClassVar
@@ -25,12 +25,24 @@ from dvsim.job.deploy import (
25
25
  from dvsim.logging import log
26
26
  from dvsim.modes import BuildMode, Mode, RunMode, find_mode
27
27
  from dvsim.regression import Regression
28
- from dvsim.report.data import FlowResults, IPMeta, Testpoint, TestResult, TestStage, ToolMeta
28
+ from dvsim.sim.data import (
29
+ IPMeta,
30
+ SimFlowResults,
31
+ SimResultsSummary,
32
+ Testpoint,
33
+ TestResult,
34
+ TestStage,
35
+ ToolMeta,
36
+ )
37
+ from dvsim.sim.report import gen_block_report, gen_reports
29
38
  from dvsim.sim_results import BucketedFailures, SimResults
30
39
  from dvsim.test import Test
31
40
  from dvsim.testplan import Testplan
32
41
  from dvsim.tool.utils import get_sim_tool_plugin
33
42
  from dvsim.utils import TS_FORMAT, rm_path
43
+ from dvsim.utils.git import git_commit_hash
44
+
45
+ __all__ = ("SimCfg",)
34
46
 
35
47
  # This affects the bucketizer failure report.
36
48
  _MAX_UNIQUE_TESTS = 5
@@ -574,13 +586,83 @@ class SimCfg(FlowCfg):
574
586
  for item in self.cfgs:
575
587
  item._cov_unr()
576
588
 
589
+ def gen_results(self, results: Sequence[CompletedJobStatus]) -> None:
590
+ """Generate flow results.
591
+
592
+ Args:
593
+ results: completed job status objects.
594
+
595
+ """
596
+ reports_dir = Path(self.scratch_base_path) / "reports"
597
+ commit = git_commit_hash(path=Path(self.proj_root))
598
+ url = f"https://github.com/lowrisc/opentitan/tree/{commit}"
599
+
600
+ all_flow_results: Mapping[str, SimFlowResults] = {}
601
+
602
+ for item in self.cfgs:
603
+ item_results = [
604
+ res
605
+ for res in results
606
+ if res.block.name == item.name and res.block.variant == item.variant
607
+ ]
608
+
609
+ flow_results: SimFlowResults = item._gen_json_results(
610
+ run_results=item_results,
611
+ commit=commit,
612
+ url=url,
613
+ )
614
+
615
+ # Convert to lowercase to match filename
616
+ block_result_index = (
617
+ f"{item.name}_{item.variant}" if item.variant else item.name
618
+ ).lower()
619
+
620
+ all_flow_results[block_result_index] = flow_results
621
+
622
+ # Generate the block's JSON/HTML reports to the report area.
623
+ gen_block_report(
624
+ results=flow_results,
625
+ path=reports_dir,
626
+ )
627
+
628
+ self.errors_seen |= item.errors_seen
629
+
630
+ if self.is_primary_cfg:
631
+ # The timestamp for this run has been taken with `utcnow()` and is
632
+ # stored in a custom format. Store it in standard ISO format with
633
+ # explicit timezone annotation.
634
+ timestamp = (
635
+ datetime.strptime(self.timestamp, "%Y%m%d_%H%M%S")
636
+ .replace(tzinfo=timezone.utc)
637
+ .isoformat()
638
+ )
639
+
640
+ results_summary = SimResultsSummary(
641
+ top=IPMeta(
642
+ name=self.name,
643
+ variant=self.variant,
644
+ commit=commit,
645
+ branch=self.branch,
646
+ url=url,
647
+ ),
648
+ timestamp=timestamp,
649
+ flow_results=all_flow_results,
650
+ report_path=reports_dir,
651
+ )
652
+
653
+ # Generate all the JSON/HTML reports to the report area.
654
+ gen_reports(
655
+ summary=results_summary,
656
+ path=reports_dir,
657
+ )
658
+
577
659
  def _gen_json_results(
578
660
  self,
579
661
  run_results: Sequence[CompletedJobStatus],
580
662
  commit: str,
581
663
  url: str,
582
- ) -> FlowResults:
583
- """Generate structured FlowResults from simulation run data.
664
+ ) -> SimFlowResults:
665
+ """Generate structured SimFlowResults from simulation run data.
584
666
 
585
667
  Args:
586
668
  run_results: completed job status.
@@ -700,7 +782,7 @@ class SimCfg(FlowCfg):
700
782
  failures = BucketedFailures.from_job_status(results=run_results)
701
783
 
702
784
  # --- Final result ---
703
- return FlowResults(
785
+ return SimFlowResults(
704
786
  block=block,
705
787
  tool=tool,
706
788
  timestamp=timestamp,
@@ -7,7 +7,7 @@
7
7
  from pathlib import Path
8
8
 
9
9
  from dvsim.logging import log
10
- from dvsim.report.data import FlowResults, ResultsSummary
10
+ from dvsim.sim.data import SimFlowResults, SimResultsSummary
11
11
  from dvsim.templates.render import render_static, render_template
12
12
 
13
13
  __all__ = (
@@ -17,7 +17,7 @@ __all__ = (
17
17
  )
18
18
 
19
19
 
20
- def gen_block_report(results: FlowResults, path: Path) -> None:
20
+ def gen_block_report(results: SimFlowResults, path: Path) -> None:
21
21
  """Generate a block report.
22
22
 
23
23
  Args:
@@ -47,7 +47,7 @@ def gen_block_report(results: FlowResults, path: Path) -> None:
47
47
  )
48
48
 
49
49
 
50
- def gen_summary_report(summary: ResultsSummary, path: Path) -> None:
50
+ def gen_summary_report(summary: SimResultsSummary, path: Path) -> None:
51
51
  """Generate a summary report.
52
52
 
53
53
  Args:
@@ -88,7 +88,7 @@ def gen_summary_report(summary: ResultsSummary, path: Path) -> None:
88
88
  )
89
89
 
90
90
 
91
- def gen_reports(summary: ResultsSummary, path: Path) -> None:
91
+ def gen_reports(summary: SimResultsSummary, path: Path) -> None:
92
92
  """Generate a full set of reports for the given regression run.
93
93
 
94
94
  Args:
@@ -0,0 +1,5 @@
1
+ # Copyright lowRISC contributors (OpenTitan project).
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Simulation Tools."""
@@ -8,7 +8,7 @@ from collections.abc import Mapping, Sequence
8
8
  from pathlib import Path
9
9
  from typing import Protocol, runtime_checkable
10
10
 
11
- from dvsim.report.data import CoverageMetrics
11
+ from dvsim.sim.data import CoverageMetrics
12
12
 
13
13
  __all__ = ("SimTool",)
14
14
 
@@ -8,7 +8,7 @@ import re
8
8
  from collections.abc import Mapping, Sequence
9
9
  from pathlib import Path
10
10
 
11
- from dvsim.report.data import CodeCoverageMetrics, CoverageMetrics
11
+ from dvsim.sim.data import CodeCoverageMetrics, CoverageMetrics
12
12
 
13
13
  __all__ = ("VCS",)
14
14
 
@@ -9,7 +9,7 @@ from collections import OrderedDict
9
9
  from collections.abc import Mapping, Sequence
10
10
  from pathlib import Path
11
11
 
12
- from dvsim.report.data import CodeCoverageMetrics, CoverageMetrics
12
+ from dvsim.sim.data import CodeCoverageMetrics, CoverageMetrics
13
13
 
14
14
  __all__ = ("Xcelium",)
15
15
 
dvsim/tool/utils.py CHANGED
@@ -5,9 +5,9 @@
5
5
  """EDA Tool base."""
6
6
 
7
7
  from dvsim.logging import log
8
- from dvsim.tool.sim import SimTool
9
- from dvsim.tool.vcs import VCS
10
- from dvsim.tool.xcelium import Xcelium
8
+ from dvsim.sim.tool.base import SimTool
9
+ from dvsim.sim.tool.vcs import VCS
10
+ from dvsim.sim.tool.xcelium import Xcelium
11
11
 
12
12
  __all__ = ("get_sim_tool_plugin",)
13
13
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dvsim
3
- Version: 1.7.1
3
+ Version: 1.7.3
4
4
  Summary: DV system
5
5
  Author: lowRISC contributors (OpenTitan project)
6
6
  License-File: LICENSE
@@ -10,29 +10,28 @@ dvsim/test.py,sha256=lMTieXHFIGEYQRJGJFsh_cP4bZ1_EadUolRWzIVmBvs,5610
10
10
  dvsim/testplan.py,sha256=Qhne2FqlU8R9UGB5o3QOufMVh1xdbKFMhtLvjvyGyts,28389
11
11
  dvsim/testplanner.py,sha256=kvgb6iAbmfaKmOLem1crKm49eygvOQX1q79Jv5UAHe0,1326
12
12
  dvsim/cli/__init__.py,sha256=vggha7pCXj7dUK4VZChIR37MhKONBcJqt3j8l9xKM_U,238
13
- dvsim/cli/admin.py,sha256=vDCMYrcSD6MQTdbB1wxsjX8_96qIsOu43yddaRjXjwA,1181
13
+ dvsim/cli/admin.py,sha256=bBnz0ZX1gd8RBTLd4CB3ZFvm08ayIjUUszI-rauxIK4,1182
14
14
  dvsim/cli/run.py,sha256=_S6ejDxGRyxMYKgNreCH6CC7vLFoJFRPmnCTPqQ6PBc,27968
15
15
  dvsim/examples/testplanner/common_testplan.hjson,sha256=IDkf3AYleDdbuEarj8FItBhg5lMgoVrfgnAMzTU9_IM,806
16
16
  dvsim/examples/testplanner/foo_dv_doc.md,sha256=AZkreUFyAehr2-6xh6Z7eRo4Eok9HFUH4TrDnByDor0,331
17
17
  dvsim/examples/testplanner/foo_sim_results.hjson,sha256=WAx9FIwS11oybfw1BU7AmY_14tRDXWtoLBxAL0ZDh8I,1642
18
18
  dvsim/examples/testplanner/foo_testplan.hjson,sha256=QQs4Egu77svReT9N3pIBSDP-xWCqoicQCo4Y_2-ZybA,2307
19
19
  dvsim/flow/__init__.py,sha256=K6yruWpqvtuLCORlnTspPxwBjsIpQhMaCfQSqqtyvTQ,185
20
- dvsim/flow/base.py,sha256=jUZkH0dzTnBAX8U1Hg6OaanGe6Xj9j_6bB1sSrrtytM,18946
20
+ dvsim/flow/base.py,sha256=2Ac15oc3rDpnAFlaKabLOMSOGwyi9ReVTd9zdeoLcgs,16602
21
21
  dvsim/flow/cdc.py,sha256=87aDKAsHNDnFs4dRkclQSJ5-Pm_djY8BlSR-nzcPAMY,558
22
- dvsim/flow/factory.py,sha256=J4Z3b2wTLn0pd944bca0wHSCCrN3ybCFkqcEMKHOuYo,3862
23
- dvsim/flow/formal.py,sha256=DVu-MkKJP-bJrfskXBIfqnL_sQTbqbDRuNiLv9_QQ2E,9935
22
+ dvsim/flow/factory.py,sha256=Wtp3o87vqbGzZwku4I2zxAizEMzNyZRgDwgj7aWjw4U,3862
23
+ dvsim/flow/formal.py,sha256=_sJIVSPNQv9-ezDcNr35r-xJKi1HKAWlCvwI4iqb3l0,10131
24
24
  dvsim/flow/hjson.py,sha256=iKR8gAHZl1XsYNkTPaePwKSkAcPgqO8BlKNBs4ER3XY,6483
25
- dvsim/flow/lint.py,sha256=2HxItKwCZK9JC6irG0vfmK5XTDw3MxdmgsSRZWEbibQ,6960
26
- dvsim/flow/one_shot.py,sha256=5YaEQZmvO-655bl1Nhp79_gCaj_h1YYVjoah1lqRcsc,5155
25
+ dvsim/flow/lint.py,sha256=mOfNHmbFMLl9sbulbygMK1ekfxdMWZwb8RQTKXUBadM,7144
26
+ dvsim/flow/one_shot.py,sha256=tRW8uXMz2OEYh1IIjpGuKh3Te5DId8Kp084CLSd9NEs,6819
27
27
  dvsim/flow/rdc.py,sha256=pu7GKw-eNd3RXdhq6oFKidBOflMtr1joAokS3SosTi4,562
28
- dvsim/flow/sim.py,sha256=iHGrJvz321WBPetGZWq_tXACRW0R8wHaVHt_Ea1E8kg,28009
29
28
  dvsim/flow/syn.py,sha256=LnwDM6dUhxNXRoTcUCbESZ2VCpBYEFdfuur3jsojejQ,15996
30
29
  dvsim/job/__init__.py,sha256=EtF6aoKkGy3sxCsfQMm2MAHgjYknmI1No90xvyjXRpY,186
31
30
  dvsim/job/data.py,sha256=dsc4bnAvTMW74m8QItCGMKJTyXa50fjTWngPtkw2lUc,4460
32
- dvsim/job/deploy.py,sha256=0J7suzihsKiFabJ5nlsa0d2hJGqO6salX11ATPfZz-A,31388
31
+ dvsim/job/deploy.py,sha256=Ec5pmsGOtxGnwcAq4qh7b2B6URjlejyf6jLNwZo_aVg,31477
33
32
  dvsim/job/time.py,sha256=RLQn16cIEGRKmRf5bQC1h1P8SaSBAIjvynyDyYrKUrY,5369
34
33
  dvsim/launcher/__init__.py,sha256=P-A-eAsx-3Nz4b3mnautm9fGV02qVelwBrNX_PGfOUw,188
35
- dvsim/launcher/base.py,sha256=adjA2_XBurCiMUWrB0vmAQIejhpwntmHNs50Ybzv6g0,15099
34
+ dvsim/launcher/base.py,sha256=TitiE4BTTkg0hcT-cKL9neYD6oudZXC0FpOGN_WpTfM,15027
36
35
  dvsim/launcher/factory.py,sha256=zs4bJ4n2TeWbbVk1IRXAazC5viNg4mPUITofP0fqHEc,2620
37
36
  dvsim/launcher/fake.py,sha256=ODtwNOzgaGYklPQPy3J69uWOlWbMGUw67sAmWQoENHQ,2426
38
37
  dvsim/launcher/local.py,sha256=eoCYkmkm-uS-zezVn4oRp7OuTwCnWr20ewtUFnxFmg8,6816
@@ -46,8 +45,15 @@ dvsim/launcher/sge/qsubopts.py,sha256=RxjgULUI_JDrdsn1VxQnBSxW0Z-4nfzP8w6l9x3tm6
46
45
  dvsim/linting/__init__.py,sha256=SOXGwiOyg_dBPIHSFwctNLKk2M84jXpDpZjjGyPmcPA,183
47
46
  dvsim/linting/parser.py,sha256=19o4F5YTh43u1s9Hx7nPeGujYgo61v44JHpPiy-e-Hw,3722
48
47
  dvsim/report/__init__.py,sha256=m58UrZ_U3jKI0QlB3r6cGdRb-QfgzN7t0udJpYa2DMs,196
49
- dvsim/report/data.py,sha256=MC9Apc3H7Cd3k0ykaJ9b3EsdZc-nfTnUaIsSPoHkesM,5829
50
- dvsim/report/generate.py,sha256=2zDJkMmpb71tlMxhopMq2vV_XDhOw2r5krSI0nZ4btQ,2634
48
+ dvsim/report/data.py,sha256=Li_FSIPT7yEdF5buLLEbx7DnTX3eHf1UZ5aBHk6C5Es,935
49
+ dvsim/sim/__init__.py,sha256=XU7GhNkaQxhHqsO_P5XDXnWURcT27iScKg630EQLJ40,195
50
+ dvsim/sim/data.py,sha256=J1PkWk2ivFZm0FLUmLexGb3KAAhgnT51KDE6oZ1FqNM,6369
51
+ dvsim/sim/flow.py,sha256=h1-zgd3_yGhODwD0EcKoknGU8xeVeWMb3uc1apQ1YI8,30552
52
+ dvsim/sim/report.py,sha256=ljpmFu_ln3plZyhNs2X2_xkRFqERk5Txhn_zXvFl4fU,2646
53
+ dvsim/sim/tool/__init__.py,sha256=VCe2PQYQUkthjXjbSVSxNALwO1t0Y6mVW6eszl_JtW4,192
54
+ dvsim/sim/tool/base.py,sha256=HQJDapJQEf6GsPGJPDsNpNA4omk7i0CqzzxT27-ytjk,2573
55
+ dvsim/sim/tool/vcs.py,sha256=qRxvr8KVaNJrcshPqpbwhCuyKq8o7dbb3X4cHh8wYSo,4813
56
+ dvsim/sim/tool/xcelium.py,sha256=z_fbSODH7IGI-5ivZQ1WPlideY9Qo2OcMra0HlJNpOM,6155
51
57
  dvsim/templates/__init__.py,sha256=vZhkgLLCkdOPjOK_wGaa2AqDLs2fZLuc3_TJK62ttA8,195
52
58
  dvsim/templates/render.py,sha256=uAc798QYvZJBugTl53XFz1nft8ZK_YFsyIK0oQWWErQ,1582
53
59
  dvsim/templates/reports/__init__.py,sha256=eu0aBRe908Or6yAc4K61fuxUx-48lhjqBpsslUtn5Z8,192
@@ -62,11 +68,8 @@ dvsim/templates/static/js/htmx.min.js,sha256=Iig-9oy3VFkU8KiKG97cclanA9HVgMHSVSF
62
68
  dvsim/tool/__init__.py,sha256=Y8HxxxI8UTJGDg07FFytr1pVujdBsbtHulthnEOZHcI,197
63
69
  dvsim/tool/ascentlint.py,sha256=reBueV8vqEgwwmcbBNncVM4Z4fAFqxqRzLv5rVgcCh8,4047
64
70
  dvsim/tool/meridianrdc.py,sha256=RKAhQ5Rk6SfSc3DurZTQJP36qSpSAIej42plGq5ApL0,9675
65
- dvsim/tool/sim.py,sha256=mttJ57FS16vXN6_r8NAFBieCjDDlNcXw-4oYaNXfQA0,2576
66
- dvsim/tool/utils.py,sha256=bBK-y1PjTzuOBoEUsCjW7XcAkHKd5fcXFWGv9060ktI,834
67
- dvsim/tool/vcs.py,sha256=G1J8N_8xQ0VHDGle16RtVhcTCanOYPtTol4rlOAs34E,4816
71
+ dvsim/tool/utils.py,sha256=lxLO1f0DdeATzW1XMQuJfzKOLVrmpyTD9lmgAmZM5U4,847
68
72
  dvsim/tool/verilator.py,sha256=MQykIh1Ua7PcCHmwxLaieuDx43B48bNWrJ_oviVHtQs,3655
69
- dvsim/tool/xcelium.py,sha256=T0X3H6_DP34jmi6IKha6S3LLbtnP9rt0qybljmcu_dk,6158
70
73
  dvsim/utils/__init__.py,sha256=UYFviDvztoGOBA6btN9xBCwRhaaagK45X4M0Kc1xQwU,1102
71
74
  dvsim/utils/check.py,sha256=b8bu_0zJHk4ieD5erlGfaG2F1GiDwadAvqB6kW4mOsU,994
72
75
  dvsim/utils/fs.py,sha256=NqPmnRlP8l2l1Cy3nAkLsPvEn_o2yQavP5dsUanQ_ZU,3859
@@ -77,8 +80,8 @@ dvsim/utils/status_printer.py,sha256=azwNWS83rI-h7OfOYPIj-Sy46aIz35L3y_Yiwkx60ZE
77
80
  dvsim/utils/subprocess.py,sha256=8jje9hmwZ_JH0zQ8JNwhsNldntgI3_SF6L5SUHQ9luo,1829
78
81
  dvsim/utils/timer.py,sha256=jD4R3wB_rBxaefiMr-k34aH325xdcoqtHHRCtSczSC8,1604
79
82
  dvsim/utils/wildcards.py,sha256=5WkByZLHyPlo5lD4rIXPuDjjrhrWqNpcTYxmQ5k294o,11701
80
- dvsim-1.7.1.dist-info/METADATA,sha256=d_FTuXXFCRV0937tGYDBw-TryFith5clFPfeYroX-9k,5882
81
- dvsim-1.7.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
82
- dvsim-1.7.1.dist-info/entry_points.txt,sha256=6A-YOJ6XYbedSfSJ5dP56lRkoHYrLanJt0AYNH9w3r0,75
83
- dvsim-1.7.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
84
- dvsim-1.7.1.dist-info/RECORD,,
83
+ dvsim-1.7.3.dist-info/METADATA,sha256=9iJYwxkuL0MfHfxrNtL1hBLXgzKpGrmDJJCCtFternM,5882
84
+ dvsim-1.7.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
85
+ dvsim-1.7.3.dist-info/entry_points.txt,sha256=6A-YOJ6XYbedSfSJ5dP56lRkoHYrLanJt0AYNH9w3r0,75
86
+ dvsim-1.7.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
87
+ dvsim-1.7.3.dist-info/RECORD,,
File without changes