Source code for pyIPCMI.ToolChain.Mentor.ModelSim

# EMACS settings: -*-	tab-width: 2; indent-tabs-mode: t; python-indent-offset: 2 -*-
# vim: tabstop=2:shiftwidth=2:noexpandtab
# kate: tab-width 2; replace-tabs off; indent-width 2;
#
# ==============================================================================
# Authors:          Patrick Lehmann
#                   Martin Zabel
#
# Python Class:     Mentor Graphics ModelSim specific classes
#
# License:
# ==============================================================================
# Copyright 2017-2018 Patrick Lehmann - Bötzingen, Germany
# Copyright 2007-2016 Technische Universität Dresden - Germany
#                     Chair of VLSI-Design, Diagnostics and Architecture
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
#
# load dependencies
from collections                import OrderedDict
from enum                       import unique, Enum
from re                         import compile as re_compile
from subprocess                 import check_output
from textwrap                   import dedent

from flags                      import Flags

from lib.Functions              import Init
from lib.CallBy                 import CallByRefParam
from pyIPCMI.Base.Exceptions    import PlatformNotSupportedException
from pyIPCMI.Base.Executable    import ExecutableArgument, ShortFlagArgument, ShortTupleArgument, StringArgument, PathArgument, CommandLineArgumentList, DryRunException, OptionalValuedFlagArgument
from pyIPCMI.Base.Logging       import Severity, LogEntry
from pyIPCMI.DataBase.Entity    import SimulationResult
from pyIPCMI.ToolChain          import ConfigurationException, EditionDescription, Edition, ToolConfiguration, ToolSelector, ToolMixIn, OutputFilteredExecutable
from pyIPCMI.ToolChain.Mentor   import MentorException
from pyIPCMI.Simulator          import PoCSimulationResultFilter, pyIPCMISimulationResultNotFoundException


__api__ = [
	'ModelSimException',
	'MentorModelSimPEEditions',
	'ModelSimEditions',
	'Configuration',
	'ModelSimPEConfiguration',
	'ModelSimSE32Configuration',
	'ModelSimSE64Configuration',
	'Selector',
	'ModelSim',
	'VHDLLibraryTool',
	'VHDLCompiler',
	'VHDLSimulator',
	'VLibFilter',
	'VComFilter',
	'VSimFilter'
]
__all__ = __api__


[docs]class ModelSimException(MentorException): pass
[docs]@unique class MentorModelSimPEEditions(Edition): """Enumeration of all ModelSim editions provided by Mentor Graphics itself.""" ModelSimPE = EditionDescription(Name="ModelSim PE", Section=None) ModelSimPEEducation = EditionDescription(Name="ModelSim PE (Student Edition)", Section=None)
[docs]@unique class ModelSimEditions(Edition): """Enumeration of all ModelSim editions provided by Mentor Graphics inclusive editions shipped by other vendors. """ ModelSimPE = EditionDescription(Name="ModelSim PE", Section="INSTALL.Mentor.ModelSimPE") ModelSimDE = EditionDescription(Name="ModelSim DE", Section="INSTALL.Mentor.ModelSimDE") ModelSimSE32 = EditionDescription(Name="ModelSim SE 32-bit", Section="INSTALL.Mentor.ModelSimSE32") ModelSimSE64 = EditionDescription(Name="ModelSim SE 64-bit", Section="INSTALL.Mentor.ModelSimSE64") ModelSimAlteraEdition = EditionDescription(Name="ModelSim Altera Edition", Section="INSTALL.Altera.ModelSimAE") ModelSimAlteraStarterEdition = EditionDescription(Name="ModelSim Altera Starter Edition", Section="INSTALL.Altera.ModelSimASE") ModelSimIntelEdition = EditionDescription(Name="ModelSim Intel Edition", Section="INSTALL.Intel.ModelSimAE") ModelSimIntelStarterEdition = EditionDescription(Name="ModelSim Intel Starter Edition", Section="INSTALL.Intel.ModelSimASE") QuestaSim = EditionDescription(Name="QuestaSim", Section="INSTALL.Mentor.QuestaSim")
[docs]class Configuration(ToolConfiguration): _vendor = "Mentor" #: The name of the tools vendor. _toolName = "Mentor ModelSim" #: The name of the tool. _multiVersionSupport = True #: Mentor ModelSim supports multiple versions installed on the same system.
[docs] def CheckDependency(self): """Check if general Mentor Graphics support is configured in pyIPCMI.""" return (len(self._host.Config['INSTALL.Mentor']) != 0)
[docs] def ConfigureForAll(self): """Configuration routine for Mentor Graphics ModelSim on all supported platforms. #. Ask if ModelSim is installed. * Pass |rarr| skip this configuration. Don't change existing settings. * Yes |rarr| collect installation information for ModelSim. * No |rarr| clear the ModelSim configuration section. #. Ask for ModelSim's version. #. Ask for ModelSim's edition (PE, PE student, SE 32-bit, SE 64-bit). #. Ask for ModelSim's installation directory. """ try: if (not self._AskInstalled("Is {0} installed on your system?".format(self._toolName))): self.ClearSection() else: # Configure ModelSim version version = self._ConfigureVersion() if self._multiVersionSupport: self.PrepareVersionedSections() sectionName = self._host.Config[self._section]['SectionName'] self._host.Config[sectionName]['Version'] = version self._ConfigureEdition() self._ConfigureInstallationDirectory() binPath = self._ConfigureBinaryDirectory() self._CheckModelSimVersion(binPath, version) self._host.LogNormal("{DARK_GREEN}{0} is now configured.{NOCOLOR}".format(self._toolName, **Init.Foreground), indent=1) except ConfigurationException: self.ClearSection() raise
[docs] def _GetModelSimVersion(self, binPath): if (self._host.Platform == "Windows"): vsimPath = binPath / "vsim.exe" else: vsimPath = binPath / "vsim" if not vsimPath.exists(): raise ConfigurationException("Executable '{0!s}' not found.".format(vsimPath)) from FileNotFoundError( str(vsimPath)) # get version and backend try: output = check_output([str(vsimPath), "-version"], universal_newlines=True) except OSError as ex: raise ConfigurationException("Error while accessing '{0!s}'.".format(vsimPath)) from ex version = None versionRegExpStr = r"^.* vsim (.+?) " versionRegExp = re_compile(versionRegExpStr) for line in output.split('\n'): if version is None: match = versionRegExp.match(line) if match is not None: version = match.group(1) print(self._section, version) self._host.Config[self._section]['Version'] = version
[docs] def _CheckModelSimVersion(self, binPath, version): if (self._host.Platform == "Windows"): vsimPath = binPath / "vsim.exe" else: vsimPath = binPath / "vsim" if not vsimPath.exists(): raise ConfigurationException("Executable '{0!s}' not found.".format(vsimPath)) from FileNotFoundError( str(vsimPath)) output = check_output([str(vsimPath), "-version"], universal_newlines=True) if str(version) not in output: raise ConfigurationException("ModelSim version mismatch. Expected version {0}.".format(version))
# def _ConfigureEdition(self): # pass
[docs] def RunPostConfigurationTasks(self): if (len(self._host.Config[self._section]) == 0): return # exit if not configured precompiledDirectory = self._host.Config['CONFIG.DirectoryNames']['PrecompiledFiles'] vSimSimulatorFiles = self._host.Config['CONFIG.DirectoryNames']['ModelSimFiles'] vsimPath = self._host.Directories.Root / precompiledDirectory / vSimSimulatorFiles modelsimIniPath = vsimPath / "modelsim.ini" if not vsimPath.exists(): self.LogVerbose("Creating directory for ModelSim files.") try: self.LogDebug("Creating directory '{0!s}'.".format(vsimPath)) vsimPath.mkdir(parents=True) except OSError as ex: raise ConfigurationException("Error while creating '{0!s}'.".format(vsimPath)) from ex else: self.LogDebug("Directory for ModelSim files already exists.") if not modelsimIniPath.exists(): self.LogVerbose("Creating initial 'modelsim.ini' file.") self.LogDebug("Writing initial 'modelsim.ini' file to '{0!s}'.".format(modelsimIniPath)) try: with modelsimIniPath.open('w') as fileHandle: fileContent = dedent("""\ [Library] others = $MODEL_TECH/../modelsim.ini """) fileHandle.write(fileContent) except OSError as ex: raise ConfigurationException("Error while creating '{0!s}'.".format(modelsimIniPath)) from ex else: self.LogVerbose("ModelSim configuration file '{0!s}' already exists.".format(modelsimIniPath))
[docs]class ModelSimPEConfiguration(Configuration): _toolName = "Mentor ModelSim PE" #: The name of the tool. _section = "INSTALL.Mentor.ModelSimPE" #: The name of the configuration section. Pattern: ``INSTALL.Vendor.ToolName``. _template = { "Windows": { _section: { "Version": "10.5c", "SectionName": ("%{PathWithRoot}#${Version}", None), "Edition": "ModelSim PE", "ToolInstallationName": "ModelSim PE", "InstallationDirectory": ("${${SectionName}:InstallationDirectory}", "${INSTALL.Mentor:InstallationDirectory}/${ToolInstallationName}/${Version}"), "BinaryDirectory": ("${${SectionName}:BinaryDirectory}", "${InstallationDirectory}/win32pe"), "AdditionalVComOptions": ("${${SectionName}:AdditionalVComOptions}", ""), "AdditionalVSimOptions": ("${${SectionName}:AdditionalVSimOptions}", "") } } } #: The template for the configuration sections represented as nested dictionaries.
[docs] def _ConfigureEdition(self): """Configure ModelSim PE for Mentor Graphics.""" sectionName = self._section if self._multiVersionSupport: sectionName = self._host.Config[sectionName]['SectionName'] configSection = self._host.Config[sectionName] defaultEdition = MentorModelSimPEEditions.Parse(configSection['Edition']) edition = super()._ConfigureEdition(MentorModelSimPEEditions, defaultEdition) if (edition is not defaultEdition): configSection['Edition'] = edition.Name self._host.Config.Interpolation.clear_cache() if self._multiVersionSupport: sectionName = self._host.Config[self._section]['SectionName'] else: sectionName = self._section configSection = self._host.Config[sectionName] binaryDirectory = self._host.Config.get(sectionName, 'BinaryDirectory', raw=True) if (edition is MentorModelSimPEEditions.ModelSimPE): toolInstallationName = "ModelSim PE" binaryDirectory = binaryDirectory.replace("win32peedu", "win32pe") elif (edition is MentorModelSimPEEditions.ModelSimPEEducation): toolInstallationName = "ModelSim PE Student Edition" binaryDirectory = binaryDirectory.replace("win32pe", "win32pe_edu") else: toolInstallationName = None configSection['ToolInstallationName'] = toolInstallationName configSection['BinaryDirectory'] = binaryDirectory
class ModelSimDEConfiguration(Configuration): _toolName = "Mentor ModelSim DE" #: The name of the tool. _section = "INSTALL.Mentor.ModelSimDE" #: The name of the configuration section. Pattern: ``INSTALL.Vendor.ToolName``. _template = { "Linux": { _section: { "Version": "10.5c", "SectionName": ("%{PathWithRoot}#${Version}", None), "Edition": "ModelSim DE", "ToolInstallationName": "ModelSim DE", "InstallationDirectory": ("${${SectionName}:InstallationDirectory}", "${INSTALL.Mentor:InstallationDirectory}/${ToolInstallationName}/${Version}"), "BinaryDirectory": ("${${SectionName}:BinaryDirectory}", "${InstallationDirectory}/linuxpe"), "AdditionalVComOptions": ("${${SectionName}:AdditionalVComOptions}", ""), "AdditionalVSimOptions": ("${${SectionName}:AdditionalVSimOptions}", "") } } } #: The template for the configuration sections represented as nested dictionaries. def _ConfigureEdition(self): pass
[docs]class ModelSimSE32Configuration(Configuration): _toolName = "Mentor ModelSim SE 32-bit" #: The name of the tool. _section = "INSTALL.Mentor.ModelSimSE32" #: The name of the configuration section. Pattern: ``INSTALL.Vendor.ToolName``. _template = { "Windows": { _section: { "Version": "10.5c", "SectionName": ("%{PathWithRoot}#${Version}", None), "Edition": "ModelSim SE 32-bit", "ToolInstallationName": "ModelSim SE", "InstallationDirectory": ("${${SectionName}:InstallationDirectory}", "${INSTALL.Mentor:InstallationDirectory}/${ToolInstallationName}/${Version}"), "BinaryDirectory": ("${${SectionName}:BinaryDirectory}", "${InstallationDirectory}/win32"), "AdditionalVComOptions": ("${${SectionName}:AdditionalVComOptions}", ""), "AdditionalVSimOptions": ("${${SectionName}:AdditionalVSimOptions}", "") } } } #: The template for the configuration sections represented as nested dictionaries.
[docs] def _ConfigureEdition(self): pass
[docs]class ModelSimSE64Configuration(Configuration): _toolName = "Mentor ModelSim SE 64-bit" #: The name of the tool. _section = "INSTALL.Mentor.ModelSimSE64" #: The name of the configuration section. Pattern: ``INSTALL.Vendor.ToolName``. _template = { "Windows": { _section: { "Version": "10.5c", "SectionName": ("%{PathWithRoot}#${Version}", None), "Edition": "ModelSim SE 64-bit", "ToolInstallationName": "ModelSim SE", "InstallationDirectory": ("${${SectionName}:InstallationDirectory}", "${INSTALL.Mentor:InstallationDirectory}/${ToolInstallationName}/${Version}"), "BinaryDirectory": ("${${SectionName}:BinaryDirectory}", "${InstallationDirectory}/win64"), "AdditionalVComOptions": ("${${SectionName}:AdditionalVComOptions}", ""), "AdditionalVSimOptions": ("${${SectionName}:AdditionalVSimOptions}", "") } }, "Linux": { _section: { "Version": "10.5c", "SectionName": ("%{PathWithRoot}#${Version}", None), "Edition": "ModelSim SE 64-bit", "ToolInstallationName": "ModelSim_SE", "InstallationDirectory": ("${${SectionName}:InstallationDirectory}", "${INSTALL.Mentor:InstallationDirectory}/${ToolInstallationName}/${Version}"), "BinaryDirectory": ("${${SectionName}:BinaryDirectory}", "${InstallationDirectory}/linux_x86_64"), "AdditionalVComOptions": ("${${SectionName}:AdditionalVComOptions}", ""), "AdditionalVSimOptions": ("${${SectionName}:AdditionalVSimOptions}", "") } } } #: The template for the configuration sections represented as nested dictionaries.
[docs] def _ConfigureEdition(self): pass
[docs]class Selector(ToolSelector): _toolName = "ModelSim"
[docs] def Select(self): editions = self._GetConfiguredEditions(ModelSimEditions) if (len(editions) == 0): self._host.LogWarning("No ModelSim installation found.", indent=1) self._host.Config['INSTALL.ModelSim'] = OrderedDict() elif (len(editions) == 1): self._host.LogNormal("Default ModelSim installation:", indent=1) self._host.LogNormal("Set to {0}".format(editions[0].Name), indent=2) self._host.Config['INSTALL.ModelSim']['SectionName'] = editions[0].Section else: self._host.LogNormal("Select ModelSim installation:", indent=1) defaultEdition = ModelSimEditions.ModelSimSE64 if defaultEdition not in editions: defaultEdition = editions[0] selectedEdition = self._AskSelection(editions, defaultEdition) self._host.Config['INSTALL.ModelSim']['SectionName'] = selectedEdition.Section
[docs]class ModelSim(ToolMixIn):
[docs] def GetVHDLLibraryTool(self): return VHDLLibraryTool(self)
[docs] def GetVHDLCompiler(self): return VHDLCompiler(self)
[docs] def GetSimulator(self): return VHDLSimulator(self)
[docs]class VHDLLibraryTool(OutputFilteredExecutable, ToolMixIn): def __init__(self, toolchain: ToolMixIn): ToolMixIn.__init__( self, toolchain._platform, toolchain._dryrun, toolchain._binaryDirectoryPath, toolchain._version, toolchain._logger) if (self._platform == "Windows"): executablePath = self._binaryDirectoryPath / "vlib.exe" elif (self._platform == "Linux"): executablePath = self._binaryDirectoryPath / "vlib" else: raise PlatformNotSupportedException(self._platform) super().__init__(self._platform, self._dryrun, executablePath, logger=self._logger) self.Parameters[self.Executable] = executablePath
[docs] class Executable(metaclass=ExecutableArgument): pass
[docs] class SwitchLibraryName(metaclass=StringArgument): pass
Parameters = CommandLineArgumentList( Executable, SwitchLibraryName )
[docs] def CreateLibrary(self): parameterList = self.Parameters.ToArgumentList() self.LogVerbose("command: {0}".format(" ".join(parameterList))) try: self.StartProcess(parameterList) except Exception as ex: raise ModelSimException("Failed to launch vlib run.") from ex self._hasOutput = False self._hasWarnings = False self._hasErrors = False try: iterator = iter(VLibFilter(self.GetReader())) line = next(iterator) line.IndentBy(self.Logger.BaseIndent + 1) self._hasOutput = True self.LogNormal("vlib messages for '{0}'".format(self.Parameters[self.SwitchLibraryName]), indent=1) self.LogNormal("-" * (78 - self.Logger.BaseIndent * 2), indent=1) self.Log(line) while True: self._hasWarnings |= (line.Severity is Severity.Warning) self._hasErrors |= (line.Severity is Severity.Error) line = next(iterator) line.IndentBy(self.Logger.BaseIndent + 1) self.Log(line) except DryRunException: pass except StopIteration: pass finally: if self._hasOutput: self.LogNormal("-" * (78 - self.Logger.BaseIndent * 2), indent=1)
class VHDLCompilerCoverageOptions(Flags): __no_flags_name__ = "Default" __all_flags_name__ = "All" Statement = "s" Branch = "b" Condition = "c" Expression = "e" StateMachine = "f" Toggle = "t" def __str__(self): return "".join([i.value for i in self]) class VHDLCompilerFSMVerbosityLevel(Enum): Default = "" Basic = "b" TransitionTable = "t" AnyWarning = "w" def __str__(self): return self.value class OptionalModelSimMinusArgument(OptionalValuedFlagArgument): _pattern = "-{0}" _patternWithValue = "-{0} {1}" class OptionalModelSimPlusArgument(OptionalValuedFlagArgument): _pattern = "+{0}" _patternWithValue = "+{0}={1}"
[docs]class VHDLCompiler(OutputFilteredExecutable, ToolMixIn): def __init__(self, toolchain : ToolMixIn): ToolMixIn.__init__( self, toolchain._platform, toolchain._dryrun, toolchain._binaryDirectoryPath, toolchain._version, toolchain._logger) if (self._platform == "Windows"): executablePath = self._binaryDirectoryPath / "vcom.exe" elif (self._platform == "Linux"): executablePath = self._binaryDirectoryPath / "vcom" else: raise PlatformNotSupportedException(self._platform) super().__init__(self._platform, self._dryrun, executablePath, logger=self._logger) self.Parameters[self.Executable] = executablePath
[docs] class Executable(metaclass=ExecutableArgument): _value = None
[docs] class FlagTime(metaclass=ShortFlagArgument): _name = "time" # Print the compilation wall clock time _value = None
[docs] class FlagExplicit(metaclass=ShortFlagArgument): _name = "explicit" _value = None
[docs] class FlagQuietMode(metaclass=ShortFlagArgument): _name = "quiet" # Do not report 'Loading...' messages" _value = None
[docs] class SwitchModelSimIniFile(metaclass=ShortTupleArgument): _name = "modelsimini" _value = None
[docs] class FlagRangeCheck(metaclass=ShortFlagArgument): _name = "rangecheck" _value = None
[docs] class SwitchCoverage(metaclass=OptionalModelSimPlusArgument): _name = "cover"
# @property # def Value(self): # return self._value # # @Value.setter # def Value(self, value): # if (value is None): self._value = None # elif isinstance(value, VHDLCompilerCoverageOptions): self._value = value # else: raise ValueError("Parameter 'value' is not of type VHDLCompilerCoverageOptions.") # # def __str__(self): # if (self._value is None): return "" # elif (self._value is VHDLCompilerCoverageOptions.Default): return self._pattern.format(self._name) # else: return self._patternWithValue.format(self._name, str(self._value)) # # def AsArgument(self): # if (self._value is None): return None # elif (self._value is VHDLCompilerCoverageOptions.Default): return self._pattern.format(self._name) # else: return self._patternWithValue.format(self._name, str(self._value))
[docs] class FlagEnableFocusedExpressionCoverage(metaclass=ShortFlagArgument): _name = "coverfec"
[docs] class FlagDisableFocusedExpressionCoverage(metaclass=ShortFlagArgument): _name = "nocoverfec"
[docs] class FlagEnableRapidExpressionCoverage(metaclass=ShortFlagArgument): _name = "coverrec"
[docs] class FlagDisableRapidExpressionCoverage(metaclass=ShortFlagArgument): _name = "nocoverrec"
[docs] class FlagEnableRecognitionOfImplicitFSMResetTransitions(metaclass=ShortFlagArgument): _name = "fsmresettrans"
[docs] class FlagDisableRecognitionOfImplicitFSMResetTransitions(metaclass=ShortFlagArgument): _name = "nofsmresettrans"
[docs] class FlagEnableRecognitionOfSingleBitFSMState(metaclass=ShortFlagArgument): _name = "fsmsingle"
[docs] class FlagDisableRecognitionOfSingleBitFSMState(metaclass=ShortFlagArgument): _name = "nofsmsingle"
[docs] class FlagEnableRecognitionOfImplicitFSMTransitions(metaclass=ShortFlagArgument): _name = "fsmimplicittrans"
[docs] class FlagDisableRecognitionOfImplicitFSMTransitions(metaclass=ShortFlagArgument): _name = "nofsmimplicittrans"
[docs] class SwitchFSMVerbosityLevel(metaclass=OptionalModelSimMinusArgument): _name = "fsmverbose"
# @property # def Value(self): # return self._value # # @Value.setter # def Value(self, value): # if (value is None): self._value = None # elif isinstance(value, VHDLCompilerFSMVerbosityLevel): self._value = value # else: raise ValueError("Parameter 'value' is not of type VHDLCompilerFSMVerbosityLevel.") # # def __str__(self): # if (self._value is None): return "" # elif (self._value is VHDLCompilerFSMVerbosityLevel.Default): return self._pattern.format(self._name) # else: return self._patternWithValue.format(self._name, str(self._value)) # # def AsArgument(self): # if (self._value is None): return None # elif (self._value is VHDLCompilerFSMVerbosityLevel.Default): return self._pattern.format(self._name) # else: return self._patternWithValue.format(self._name, str(self._value))
[docs] class FlagReportAsNote(metaclass=ShortTupleArgument): _name = "note" _value = None
[docs] class FlagReportAsError(metaclass=ShortTupleArgument): _name = "error" _value = None
[docs] class FlagReportAsWarning(metaclass=ShortTupleArgument): _name = "warning" _value = None
[docs] class FlagReportAsFatal(metaclass=ShortTupleArgument): _name = "fatal" _value = None
[docs] class FlagRelaxLanguageChecks(metaclass=ShortFlagArgument): _name = "permissive"
[docs] class FlagForceLanguageChecks(metaclass=ShortFlagArgument): _name = "pedanticerrors"
[docs] class SwitchVHDLVersion(metaclass=StringArgument): _pattern = "-{0}" _value = None
[docs] class ArgLogFile(metaclass=ShortTupleArgument): _name = "l" # what's the difference to -logfile ? _value = None
[docs] class SwitchVHDLLibrary(metaclass=ShortTupleArgument): _name = "work" _value = None
[docs] class ArgSourceFile(metaclass=PathArgument): _value = None
Parameters = CommandLineArgumentList( Executable, FlagTime, FlagExplicit, FlagQuietMode, SwitchModelSimIniFile, FlagRangeCheck, SwitchCoverage, FlagEnableFocusedExpressionCoverage, FlagDisableFocusedExpressionCoverage, FlagEnableRapidExpressionCoverage, FlagDisableRapidExpressionCoverage, FlagEnableRecognitionOfImplicitFSMResetTransitions, FlagDisableRecognitionOfImplicitFSMResetTransitions, FlagEnableRecognitionOfSingleBitFSMState, FlagDisableRecognitionOfSingleBitFSMState, FlagEnableRecognitionOfImplicitFSMTransitions, FlagDisableRecognitionOfImplicitFSMTransitions, SwitchFSMVerbosityLevel, FlagReportAsNote, FlagReportAsError, FlagReportAsWarning, FlagReportAsFatal, FlagRelaxLanguageChecks, FlagForceLanguageChecks, SwitchVHDLVersion, ArgLogFile, SwitchVHDLLibrary, ArgSourceFile )
[docs] def Compile(self): parameterList = self.Parameters.ToArgumentList() self.LogVerbose("command: {0}".format(" ".join(parameterList))) if (self._dryrun): self.LogDryRun("Start process: {0}".format(" ".join(parameterList))) return try: self.StartProcess(parameterList) except Exception as ex: raise ModelSimException("Failed to launch vcom run.") from ex self._hasOutput = False self._hasWarnings = False self._hasErrors = False try: iterator = iter(VComFilter(self.GetReader())) line = next(iterator) line.IndentBy(self.Logger.BaseIndent + 1) self._hasOutput = True self.LogNormal("vcom messages for '{0}'".format(self.Parameters[self.ArgSourceFile]), indent=1) self.LogNormal("-" * (78 - self.Logger.BaseIndent*2), indent=1) self.Log(line) while True: self._hasWarnings |= (line.Severity is Severity.Warning) self._hasErrors |= (line.Severity is Severity.Error) line = next(iterator) line.IndentBy(self.Logger.BaseIndent + 1) self.Log(line) except DryRunException: pass except StopIteration: pass finally: if self._hasOutput: self.LogNormal("-" * (78 - self.Logger.BaseIndent*2), indent=1)
[docs] def GetTclCommand(self): parameterList = self.Parameters.ToArgumentList() return "vcom " + " ".join(parameterList[1:])
[docs]class VHDLSimulator(OutputFilteredExecutable, ToolMixIn): def __init__(self, toolchain : ToolMixIn): ToolMixIn.__init__( self, toolchain._platform, toolchain._dryrun, toolchain._binaryDirectoryPath, toolchain._version, toolchain._logger) if (self._platform == "Windows"): executablePath = self._binaryDirectoryPath / "vsim.exe" elif (self._platform == "Linux"): executablePath = self._binaryDirectoryPath / "vsim" else: raise PlatformNotSupportedException(self._platform) super().__init__(self._platform, self._dryrun, executablePath, logger=self._logger) self.Parameters[self.Executable] = executablePath
[docs] class Executable(metaclass=ExecutableArgument): """The executable to launch.""" _value = None
[docs] class FlagQuietMode(metaclass=ShortFlagArgument): """Run simulation in quiet mode. (Don't show 'Loading...' messages.""" _name = "quiet" _value = None
[docs] class FlagBatchMode(metaclass=ShortFlagArgument): """Run simulation in batch mode.""" _name = "batch" _value = None
[docs] class FlagGuiMode(metaclass=ShortFlagArgument): """Run simulation in GUI mode.""" _name = "gui" _value = None
[docs] class SwitchBatchCommand(metaclass=ShortTupleArgument): """Specify a Tcl batch script for the batch mode.""" _name = "do" _value = None
[docs] class FlagCommandLineMode(metaclass=ShortFlagArgument): """Run simulation in command line mode.""" _name = "c" _value = None
[docs] class SwitchModelSimIniFile(metaclass=ShortTupleArgument): """Specify the used 'modelsim.ini' file.""" _name = "modelsimini" _value = None
[docs] class FlagEnableOptimization(metaclass=ShortFlagArgument): """Enabled optimization while elaborating the design.""" _name = "vopt"
[docs] class FlagDisableOptimization(metaclass=ShortFlagArgument): """Disabled optimization while elaborating the design.""" _name = "novopt"
[docs] class FlagEnableOptimizationVerbosity(metaclass=ShortFlagArgument): """Enabled optimization while elaborating the design.""" _name = "vopt_verbose"
[docs] class FlagEnableKeepAssertionCountsForCoverage(metaclass=ShortFlagArgument): _name = "assertcover"
[docs] class FlagDisableKeepAssertionCountsForCoverage(metaclass=ShortFlagArgument): _name = "noassertcover"
[docs] class FlagEnableCoverage(metaclass=ShortFlagArgument): _name = "coverage"
[docs] class FlagDisableCoverage(metaclass=ShortFlagArgument): _name = "nocoverage"
[docs] class FlagEnablePSL(metaclass=ShortFlagArgument): _name = "psl"
[docs] class FlagDisablePSL(metaclass=ShortFlagArgument): _name = "nopsl"
[docs] class FlagEnableFSMDebugging(metaclass=ShortFlagArgument): _name = "fsmdebug"
[docs] class FlagReportAsNote(metaclass=ShortTupleArgument): _name = "note" _value = None
[docs] class FlagReportAsError(metaclass=ShortTupleArgument): _name = "error" _value = None
[docs] class FlagReportAsWarning(metaclass=ShortTupleArgument): _name = "warning" _value = None
[docs] class FlagReportAsFatal(metaclass=ShortTupleArgument): _name = "fatal" _value = None
[docs] class FlagRelaxLanguageChecks(metaclass=ShortFlagArgument): _name = "permissive"
[docs] class FlagForceLanguageChecks(metaclass=ShortFlagArgument): _name = "pedanticerrors"
[docs] class SwitchTimeResolution(metaclass=ShortTupleArgument): """Set simulation time resolution.""" _name = "t" # -t [1|10|100]fs|ps|ns|us|ms|sec Time resolution limit _value = None
[docs] class ArgLogFile(metaclass=ShortTupleArgument): _name = "l" # what's the difference to -logfile ? _value = None
[docs] class ArgKeepStdOut(metaclass=ShortFlagArgument): _name = "keepstdout"
[docs] class ArgVHDLLibraryName(metaclass=ShortTupleArgument): _name = "lib" _value = None
[docs] class ArgOnFinishMode(metaclass=ShortTupleArgument): _name = "onfinish" _value = None # Customize the kernel shutdown behavior at the end of simulation; Valid modes: ask, stop, exit, final (Default: ask)
[docs] class SwitchTopLevel(metaclass=StringArgument): """The top-level for simulation.""" _value = None
#: Specify all accepted command line arguments Parameters = CommandLineArgumentList( Executable, FlagQuietMode, FlagBatchMode, FlagGuiMode, SwitchBatchCommand, FlagCommandLineMode, SwitchModelSimIniFile, FlagEnableOptimization, FlagDisableOptimization, FlagEnableOptimizationVerbosity, FlagEnableKeepAssertionCountsForCoverage, FlagDisableKeepAssertionCountsForCoverage, FlagEnableCoverage, FlagDisableCoverage, FlagEnablePSL, FlagDisablePSL, FlagEnableFSMDebugging, FlagReportAsNote, FlagReportAsError, FlagReportAsWarning, FlagReportAsFatal, FlagRelaxLanguageChecks, FlagForceLanguageChecks, ArgLogFile, ArgKeepStdOut, ArgVHDLLibraryName, SwitchTimeResolution, ArgOnFinishMode, SwitchTopLevel )
[docs] def Simulate(self): """Start a simulation.""" parameterList = self.Parameters.ToArgumentList() self.LogVerbose("command: {0}".format(" ".join(parameterList))) try: self.StartProcess(parameterList) except Exception as ex: raise ModelSimException("Failed to launch vsim run.") from ex self._hasOutput = False self._hasWarnings = False self._hasErrors = False simulationResult = CallByRefParam(SimulationResult.Error) try: iterator = iter(PoCSimulationResultFilter(VSimFilter(self.GetReader()), simulationResult)) line = next(iterator) line.IndentBy(self.Logger.BaseIndent + 1) self._hasOutput = True self.LogNormal("vsim messages for '{0}'".format(self.Parameters[self.SwitchTopLevel]), indent=1) self.LogNormal("-" * (78 - self.Logger.BaseIndent*2), indent=1) self.Log(line) while True: self._hasWarnings |= (line.Severity is Severity.Warning) self._hasErrors |= (line.Severity is Severity.Error) line = next(iterator) line.IndentBy(self.Logger.BaseIndent + 1) self.Log(line) except DryRunException: simulationResult <<= SimulationResult.DryRun except pyIPCMISimulationResultNotFoundException: if self.Parameters[self.FlagGuiMode]: simulationResult <<= SimulationResult.GUIRun except StopIteration: pass finally: if self._hasOutput: self.LogNormal("-" * (78 - self.Logger.BaseIndent*2), indent=1) return simulationResult.value
[docs]def VLibFilter(gen): for line in gen: if line.startswith("** Warning: "): yield LogEntry(line, Severity.Warning) elif line.startswith("** Error"): yield LogEntry(line, Severity.Error) elif line.startswith("** Fatal: "): yield LogEntry(line, Severity.Error) else: yield LogEntry(line, Severity.Normal)
[docs]def VComFilter(gen): for line in gen: if line.startswith("** Warning: "): yield LogEntry(line, Severity.Warning) elif line.startswith("** Error"): yield LogEntry(line, Severity.Error) elif line.startswith("** Fatal: "): yield LogEntry(line, Severity.Error) else: yield LogEntry(line, Severity.Normal)
[docs]def VSimFilter(gen): pyIPCMIOutputFound = False for line in gen: if line.startswith("# Loading "): yield LogEntry(line, Severity.Debug) elif line.startswith("# //"): if line[6:].startswith("Questa"): yield LogEntry(line, Severity.Debug) elif line[6:].startswith("Version "): yield LogEntry(line, Severity.Debug) else: continue elif line.startswith("# ========================================"): pyIPCMIOutputFound = True yield LogEntry(line[2:], Severity.Normal) elif line.startswith("# ** Warning: "): yield LogEntry(line, Severity.Warning) elif line.startswith("# ** Error"): yield LogEntry(line, Severity.Error) elif line.startswith("# ** Fatal: "): yield LogEntry(line, Severity.Error) elif line.startswith("** Fatal: "): yield LogEntry(line, Severity.Error) elif line.startswith("# %%"): if ("ERROR" in line): yield LogEntry("{DARK_RED}{line}{NOCOLOR}".format(line=line[2:], **Init.Foreground), Severity.Error) else: yield LogEntry("{DARK_CYAN}{line}{NOCOLOR}".format(line=line[2:], **Init.Foreground), Severity.Normal) elif line.startswith("# "): if (not pyIPCMIOutputFound): yield LogEntry(line, Severity.Verbose) else: yield LogEntry(line[2:], Severity.Normal) else: yield LogEntry(line, Severity.Normal)