Coverage for pyEDAA / CLITool / NVC.py: 86%
157 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-23 22:25 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-23 22:25 +0000
1# ==================================================================================================================== #
2# _____ ____ _ _ ____ _ ___ _____ _ #
3# _ __ _ _| ____| _ \ / \ / \ / ___| | |_ _|_ _|__ ___ | | #
4# | '_ \| | | | _| | | | |/ _ \ / _ \ | | | | | | | |/ _ \ / _ \| | #
5# | |_) | |_| | |___| |_| / ___ \ / ___ \ | |___| |___ | | | | (_) | (_) | | #
6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)____|_____|___| |_|\___/ \___/|_| #
7# |_| |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2025-2026 Patrick Lehmann - Boetzingen, Germany #
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
35from pyTooling.Decorators import export
36from pyTooling.MetaClasses import ExtendedType
37from pyVHDLModel import VHDLVersion
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
48from pyEDAA.CLITool import CLIToolException
51@export
52class NVCVersion(metaclass=ExtendedType, slots=True):
53 """
55 .. code-block::
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
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 )
84 def __init__(self, versionLine: str) -> None:
85 match = re_search("^" + self.VERSION_LINE_PATTERN + "$", versionLine)
86 if match is None: 86 ↛ 87line 86 didn't jump to line 87 because the condition on line 86 was never true
87 raise CLIToolException(f"Unknown NVC version string '{versionLine}'.")
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"]
103 @property
104 def Major(self) -> int:
105 return self._major
107 @property
108 def Minor(self) -> int:
109 return self._minor
111 @property
112 def Micro(self) -> int:
113 return self._micro
115 @property
116 def CommitsSinceLastTag(self) -> int:
117 return self._commitsSinceLastTag
119 @property
120 def GitHash(self) -> str:
121 return self._gitHash
123 @property
124 def Dirty(self) -> bool:
125 return self._dirty
127 @property
128 def Backend(self) -> str:
129 return self._backend
131 def __str__(self) -> str:
132 # dev = f"-dev" if self._dev else ""
133 return f"{self._major}.{self._minor}.{self._micro}" # {dev}"
135 def __repr__(self) -> str:
136 return f"{self.__str__()} (Backend: {self._backend}; Git: {self._gitHash})"
139@export
140class NVC(Executable):
141 _executableNames = {
142 "Darwin": "nvc",
143 "FreeBSD": "nvc",
144 "Linux": "nvc",
145 "Windows": "nvc.exe"
146 }
148 @CLIArgument()
149 class CommandHelp(LongCommand, name="help"):
150 """Display usage summary."""
152 @CLIArgument()
153 class CommandVersion(LongCommand, name="version"):
154 """Display version and copyright information."""
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 """
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 """
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 """
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 """
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. The default is
187 16 megabytes but this may be insufficient when elaborating a large design. The size parameter takes an optional k,
188 m, or g suffix to indicate kilobytes, megabytes, and gigabytes respectively. For example -M64m for 64 megabytes.
189 """
191 @CLIArgument()
192 class FlagLibraryMapping(LongKeyValueFlag, name="map", pattern="--{0}={1}:{2}"):
193 """
194 Specify exactly the location of the logical library name. Libraries mapped in this way will not use the normal
195 search path.
196 """
198 @CLIArgument()
199 class FlagMessages(LongValuedFlag, name="messages"):
200 """
201 Select the format used for printing error and informational messages. The default full message format is designed
202 for readability whereas the compact messages can be easily parsed by tools.
203 """
205 @CLIArgument()
206 class FlagRandomSeed(LongValuedFlag, name="seed"):
207 """
208 Seed for random number generation. Affects the ‘get_random’ function in the ‘nvc.random’ package, the ``--shuffle``
209 option, and PSL union expressions.
210 """
212 @CLIArgument()
213 class FlagVHDLStandard(LongValuedFlag, name="std"):
214 """
215 Select the VHDL standard revision to use. VHDL standard revisions are commonly referred to by the year they were
216 published. For example IEEE 1076-1993 is known as VHDL-93. Specify either the full year such as 1993 or just the
217 last two digits such as ``93``. The accepted revisions are 1993, 2000, 2002, 2008, 2019. Note there is very limited
218 supported VHDL-2019 at present and VHDL-87 is not supported. The default standard revision is VHDL-2008.
219 """
220 _value: VHDLVersion
222 def __init__(self, value: VHDLVersion):
223 if value is None: 223 ↛ 224line 223 didn't jump to line 224 because the condition on line 223 was never true
224 raise ValueError(f"") # FIXME: add message
226 self._value = value
228 @property
229 def Value(self) -> VHDLVersion:
230 return self._value
232 @Value.setter
233 def Value(self, value: VHDLVersion) -> None:
234 if value is None:
235 raise ValueError(f"") # FIXME: add message
237 self._value = value
239 def AsArgument(self) -> Union[str, Iterable[str]]:
240 if self._name is None: 240 ↛ 241line 240 didn't jump to line 241 because the condition on line 240 was never true
241 raise ValueError(f"") # FIXME: add message
243 return self._pattern.format(self._name, str(self._value)[-2:])
245 @CLIArgument()
246 class FlagRandomSeed(LongValuedFlag, name="stderr"):
247 """
248 Print error messages with the given severity or higher to ‘stderr’ instead of ‘stdout’. The default is to print all
249 messages to ‘stderr’. Valid levels are note, warning, error, failure, and none.
250 """
252 @CLIArgument()
253 class FlagLibrary(LongValuedFlag, name="work"):
254 """
255 Use name as the work library. The second variant explicitly specifies the location of the library.
256 """
258 @CLIArgument()
259 class CommandTCLScript(LongTupleFlag, name="do"):
260 """
261 Evaluate a batch TCL script, optionally with *unit* loaded.
262 """
264 @CLIArgument()
265 class CommandAnalyze(ShortFlag, name="a"):
266 """Analyze VHDL source file(s)."""
268 @CLIArgument()
269 class OptionPaths(PathListArgument):
270 """Add list of VHDL files to analyze."""
272 @CLIArgument()
273 class FlagRelaxed(LongFlag, name="relaxed"):
274 """Relax some LRM rules."""
276 @CLIArgument()
277 class CommandElaborate(ShortTupleFlag, name="e"):
278 """Elaborate design."""
280 @CLIArgument()
281 class CommandRun(ShortTupleFlag, name="r"):
282 """Simulate design."""
290 def _CopyParameters(self, tool: "NVC") -> None:
291 for key in self.__cliParameters__:
292 if self._NeedsParameterInitialization(key):
293 value = self.__cliParameters__[key].Value
294 tool.__cliParameters__[key] = key(value)
295 else:
296 tool.__cliParameters__[key] = key()
298 def _SetParameters(self, tool: "NVC", std: Nullable[VHDLVersion] = None):
299 if std is not None: 299 ↛ 300line 299 didn't jump to line 300 because the condition on line 299 was never true
300 tool[self.FlagVHDLStandard] = str(std)
302 def GetNVCAsAnalyzer(self, std: Nullable[VHDLVersion] = None) -> "NVC":
303 tool = NVC(executablePath=self._executablePath)
305 tool[tool.CommandAnalyze] = True
306 self._CopyParameters(tool)
307 self._SetParameters(tool, std)
309 return tool
311 def GetNVCAsElaborator(self, std: Nullable[VHDLVersion] = None) -> "NVC":
312 tool = NVC(executablePath=self._executablePath)
314 tool[tool.CommandElaborate] = True
315 self._CopyParameters(tool)
316 self._SetParameters(tool, std)
318 return tool
320 def GetNVCAsSimulator(self, std: Nullable[VHDLVersion] = None) -> "NVC":
321 tool = NVC(executablePath=self._executablePath)
323 tool[tool.CommandRun] = True
324 self._CopyParameters(tool)
325 self._SetParameters(tool, std)
327 return tool
329 def Help(self) -> str:
330 tool = NVC(executablePath=self._executablePath)
332 tool[tool.CommandHelp] = True
334 tool.StartProcess()
335 return "\n".join(tool.GetLineReader())
337 def Version(self) -> NVCVersion:
338 tool = NVC(executablePath=self._executablePath)
340 tool[tool.CommandVersion] = True
342 tool.StartProcess()
343 iterator = iter(tool.GetLineReader())
344 firstLine = next(iterator)
346 return NVCVersion(firstLine)