NVC.py
Summary
- Lines:
132 of 150 covered (88.0%)
- Branches:
10 of 16 taken (62.5%), 4 lines partially
- Coverage:
85.5%
- Directory:
- Missed lines:
87, 125, 228, 238-241, 245, 304, 316-322, 325-331
Source
pyEDAA/CLITool/NVC.pycoveredpartialuncoveredexcludednot executable
1# ==================================================================================================================== #
2# _____ ____ _ _ ____ _ ___ _____ _ #
3# _ __ _ _| ____| _ \ / \ / \ / ___| | |_ _|_ _|__ ___ | | #
4# | '_ \| | | | _| | | | |/ _ \ / _ \ | | | | | | | |/ _ \ / _ \| | #
5# | |_) | |_| | |___| |_| / ___ \ / ___ \ | |___| |___ | | | | (_) | (_) | | #
6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)____|_____|___| |_|\___/ \___/|_| #
7# |_| |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2026-2026 Electronic Design Automation Abstraction (EDA²) #
15# #
16# Licensed under the Apache License, Version 2.0 (the "License"); #
17# you may not use this file except in compliance with the License. #
18# You may obtain a copy of the License at #
19# #
20# http://www.apache.org/licenses/LICENSE-2.0 #
21# #
22# Unless required by applicable law or agreed to in writing, software #
23# distributed under the License is distributed on an "AS IS" BASIS, #
24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
25# See the License for the specific language governing permissions and #
26# limitations under the License. #
27# #
28# SPDX-License-Identifier: Apache-2.0 #
29# ==================================================================================================================== #
30#
31"""This module contains the CLI abstraction layer for `NVC <https://github.com/nickg/nvc>`__."""
32from re import search as re_search
33from typing import Union, Iterable, Optional as Nullable
34
35from pyTooling.Decorators import export
36from pyTooling.MetaClasses import ExtendedType
37from pyVHDLModel import VHDLVersion
38
39from pyTooling.CLIAbstraction import CLIArgument, Executable
40from pyTooling.CLIAbstraction.Argument import PathListArgument, StringArgument
41from pyTooling.CLIAbstraction.Command import LongCommand
42from pyTooling.CLIAbstraction.Flag import ShortFlag, LongFlag
43from pyTooling.CLIAbstraction.BooleanFlag import LongBooleanFlag
44from pyTooling.CLIAbstraction.ValuedFlag import ShortValuedFlag, LongValuedFlag
45from pyTooling.CLIAbstraction.ValuedTupleFlag import LongTupleFlag, ShortTupleFlag
46from pyTooling.CLIAbstraction.KeyValueFlag import ShortKeyValueFlag, LongKeyValueFlag
47
48from pyEDAA.CLITool import CLIToolException
49
50
51@export
52class NVCVersion(metaclass=ExtendedType, slots=True):
53 """
54
55 .. code-block::
56
57 nvc 1.18.2 (1.18.2.r0.g8893318a) (Using LLVM 21.1.5)
58 Copyright (C) 2011-2025 Nick Gasson
59 This program comes with ABSOLUTELY NO WARRANTY. This is free software, and
60 you are welcome to redistribute it under certain conditions. See the GNU
61 General Public Licence for details.
62 """
63 _major: int
64 _minor: int
65 _micro: int
66 # _dev: bool
67 _commitsSinceLastTag: int
68 _gitHash: str
69 _backend: str
70
71 VERSION_LINE_PATTERN = (
72 r"nvc"
73 r"\s(?P<Major>\d+)\.(?P<Minor>\d+)\.(?P<Micro>\d+)(?:-(?P<Suffix>dev|rc\d+))?"
74 r"\s\((?:"
75 r"(?:"
76 r"(?P<major2>\d+)\.(?P<minor2>\d+)\.(?P<micro2>\d+)\.(?:r(?P<cslt>\d+))\.(?:g(?P<Hash>[0-9a-f]+))(?:\.(?P<Dirty>dirty))?"
77 r")|(?:"
78 r"(?P<Hash2>[0-9a-f]{7})"
79 r")"
80 r")\)"
81 r"\s\(Using (?P<Backend>\w+) (?P<BackendMajor>\d+)\.(?P<BackendMinor>\d+)\.(?P<BackendMicro>\d+)\)"
82 )
83
84 def __init__(self, versionLine: str) -> None:
85 match = re_search("^" + self.VERSION_LINE_PATTERN + "$", versionLine)
86 if match is None:
87 raise CLIToolException(f"Unknown NVC version string '{versionLine}'.")
88
89 self._major = int(match["Major"])
90 self._minor = int(match["Minor"])
91 self._micro = int(match["Micro"])
92 # if (suffix := match["Suffix"]) is not None:
93 # self._dev = suffix == "dev"
94 # else:
95 # self._dev = False
96 if (cslt := match["cslt"]) is not None:
97 self._commitsSinceLastTag = int(cslt)
98 else:
99 self._commitsSinceLastTag = 0
100 self._gitHash = match["Hash"] if match["Hash"] is not None else match["Hash2"]
101 self._backend = match["Backend"]
102
103 @property
104 def Major(self) -> int:
105 return self._major
106
107 @property
108 def Minor(self) -> int:
109 return self._minor
110
111 @property
112 def Micro(self) -> int:
113 return self._micro
114
115 @property
116 def CommitsSinceLastTag(self) -> int:
117 return self._commitsSinceLastTag
118
119 @property
120 def GitHash(self) -> str:
121 return self._gitHash
122
123 @property
124 def Dirty(self) -> bool:
125 return self._dirty
126
127 @property
128 def Backend(self) -> str:
129 return self._backend
130
131 def __str__(self) -> str:
132 # dev = f"-dev" if self._dev else ""
133 return f"{self._major}.{self._minor}.{self._micro}" # {dev}"
134
135 def __repr__(self) -> str:
136 return f"{self.__str__()} (Backend: {self._backend}; Git: {self._gitHash})"
137
138
139@export
140class NVC(Executable):
141 _EXECUTABLE_NAMES = {
142 "Darwin": "nvc",
143 "FreeBSD": "nvc",
144 "Linux": "nvc",
145 "Windows": "nvc.exe"
146 }
147
148 @CLIArgument()
149 class CommandHelp(LongCommand, name="help"):
150 """Display usage summary."""
151
152 @CLIArgument()
153 class CommandVersion(LongCommand, name="version"):
154 """Display version and copyright information."""
155
156 @CLIArgument()
157 class FlagSimulationHeapSize(ShortTupleFlag, name="H"):
158 """
159 Set the maximum size in bytes of the simulation heap. This area of memory is used for temporary allocations during
160 process execution and dynamic allocations by the VHDL ‘new’ operator. The size parameter takes an optional k, m, or
161 g suffix to indicate kilobytes, megabytes, and gigabytes respectively. The default size is 16 megabytes.
162 """
163
164 @CLIArgument()
165 class FlagIEEEWarnings(LongValuedFlag, name="ieee-warnings"):
166 """
167 Enable or disable warning messages from the standard IEEE packages. The off-at-0 option disables warnings in the
168 first time step only. The default is warnings enabled.
169 """
170
171 @CLIArgument()
172 class FlagIgnoreTime(LongFlag, name="ignore-time"):
173 """
174 Do not check the timestamps of source files when the corresponding design unit is loaded from a library.
175 """
176
177 @CLIArgument()
178 class FlagLibrarySearchPath(ShortTupleFlag, name="L"):
179 """
180 Add path to the list of directories to search for libraries. See the LIBRARIES section below for details.
181 """
182
183 @CLIArgument()
184 class FlagMaxMemorySize(ShortTupleFlag, name="M"):
185 """
186 Set the maximum amount of memory in bytes used for the internal representations of design units.
187
188 The default is 16 megabytes but this may be insufficient when elaborating a large design. The size parameter takes
189 an optional k, m, or g suffix to indicate kilobytes, megabytes, and gigabytes respectively. For example -M64m for 64
190 megabytes.
191 """
192
193 @CLIArgument()
194 class FlagLibraryMapping(LongKeyValueFlag, name="map", pattern="--{0}={1}:{2}"):
195 """
196 Specify exactly the location of the logical library name. Libraries mapped in this way will not use the normal
197 search path.
198 """
199
200 @CLIArgument()
201 class FlagMessages(LongValuedFlag, name="messages"):
202 """
203 Select the format used for printing error and informational messages. The default full message format is designed
204 for readability whereas the compact messages can be easily parsed by tools.
205 """
206
207 @CLIArgument()
208 class FlagRandomSeed(LongValuedFlag, name="seed"):
209 """
210 Seed for random number generation. Affects the ‘get_random’ function in the ‘nvc.random’ package, the ``--shuffle``
211 option, and PSL union expressions.
212 """
213
214 @CLIArgument()
215 class FlagVHDLStandard(LongValuedFlag, name="std"):
216 """
217 Select the VHDL standard revision to use.
218
219 VHDL standard revisions are commonly referred to by the year they were published. For example IEEE 1076-1993 is
220 known as VHDL-93. Specify either the full year such as 1993 or just the last two digits such as ``93``. The
221 accepted revisions are 1993, 2000, 2002, 2008, 2019. Note there is very limited supported VHDL-2019 at present and
222 VHDL-87 is not supported. The default standard revision is VHDL-2008.
223 """
224 _value: VHDLVersion
225
226 def __init__(self, value: VHDLVersion):
227 if value is None:
228 raise ValueError("") # FIXME: add message
229
230 self._value = value
231
232 @property
233 def Value(self) -> VHDLVersion:
234 return self._value
235
236 @Value.setter
237 def Value(self, value: VHDLVersion) -> None:
238 if value is None:
239 raise ValueError("") # FIXME: add message
240
241 self._value = value
242
243 def AsArgument(self) -> Union[str, Iterable[str]]:
244 if self._NAME is None:
245 raise ValueError("") # FIXME: add message
246
247 return self._PATTERN.format(self._NAME, str(self._value)[-2:])
248
249 @CLIArgument()
250 class FlagRandomSeed(LongValuedFlag, name="stderr"):
251 """
252 Print error messages with the given severity or higher to ‘stderr’ instead of ‘stdout’. The default is to print all
253 messages to ‘stderr’. Valid levels are note, warning, error, failure, and none.
254 """
255
256 @CLIArgument()
257 class FlagLibrary(LongValuedFlag, name="work"):
258 """
259 Use name as the work library. The second variant explicitly specifies the location of the library.
260 """
261
262 @CLIArgument()
263 class CommandTCLScript(LongTupleFlag, name="do"):
264 """
265 Evaluate a batch TCL script, optionally with *unit* loaded.
266 """
267
268 @CLIArgument()
269 class CommandAnalyze(ShortFlag, name="a"):
270 """Analyze VHDL source file(s)."""
271
272 @CLIArgument()
273 class OptionPaths(PathListArgument):
274 """Add list of VHDL files to analyze."""
275
276 @CLIArgument()
277 class FlagRelaxed(LongFlag, name="relaxed"):
278 """Relax some LRM rules."""
279
280 @CLIArgument()
281 class CommandElaborate(ShortTupleFlag, name="e"):
282 """Elaborate design."""
283
284 @CLIArgument()
285 class CommandRun(ShortTupleFlag, name="r"):
286 """Simulate design."""
287
288
289
290
291
292
293
294 def _CopyParameters(self, tool: "NVC") -> None:
295 for key in self.__cliParameters__:
296 if self._NeedsParameterInitialization(key):
297 value = self.__cliParameters__[key].Value
298 tool.__cliParameters__[key] = key(value)
299 else:
300 tool.__cliParameters__[key] = key()
301
302 def _SetParameters(self, tool: "NVC", std: Nullable[VHDLVersion] = None):
303 if std is not None:
304 tool[self.FlagVHDLStandard] = str(std)
305
306 def GetNVCAsAnalyzer(self, std: Nullable[VHDLVersion] = None) -> "NVC":
307 tool = NVC(executablePath=self._executablePath)
308
309 tool[tool.CommandAnalyze] = True
310 self._CopyParameters(tool)
311 self._SetParameters(tool, std)
312
313 return tool
314
315 def GetNVCAsElaborator(self, std: Nullable[VHDLVersion] = None) -> "NVC":
316 tool = NVC(executablePath=self._executablePath)
317
318 tool[tool.CommandElaborate] = True
319 self._CopyParameters(tool)
320 self._SetParameters(tool, std)
321
322 return tool
323
324 def GetNVCAsSimulator(self, std: Nullable[VHDLVersion] = None) -> "NVC":
325 tool = NVC(executablePath=self._executablePath)
326
327 tool[tool.CommandRun] = True
328 self._CopyParameters(tool)
329 self._SetParameters(tool, std)
330
331 return tool
332
333 def Help(self) -> str:
334 tool = NVC(executablePath=self._executablePath)
335
336 tool[tool.CommandHelp] = True
337
338 tool.StartProcess()
339 return "\n".join(tool.GetLineReader())
340
341 def Version(self) -> NVCVersion:
342 tool = NVC(executablePath=self._executablePath)
343
344 tool[tool.CommandVersion] = True
345
346 tool.StartProcess()
347 iterator = iter(tool.GetLineReader())
348 firstLine = next(iterator)
349
350 return NVCVersion(firstLine)