Source code for Simulator.QuestaSimulator

# 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 Module:    Mentor QuestaSim simulator.
#
# License:
# ==============================================================================
# Copyright 2007-2016 Technische Universitaet 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 pathlib                      import Path
from textwrap                     import dedent

from Base.Project                 import FileTypes, ToolChain, Tool
from DataBase.Config              import Vendors
from ToolChains.Mentor.QuestaSim  import QuestaSim, QuestaSimException
from Simulator                    import VHDL_TESTBENCH_LIBRARY_NAME, SimulatorException, SkipableSimulatorException, SimulationSteps, Simulator as BaseSimulator


__api__ = [
	'Simulator'
]
__all__ = __api__


[docs]class Simulator(BaseSimulator): TOOL_CHAIN = ToolChain.Mentor_QuestaSim TOOL = Tool.Mentor_vSim def __init__(self, host, dryRun, simulationSteps): # A separate elaboration step is not implemented in QuestaSim simulationSteps &= ~SimulationSteps.Elaborate super().__init__(host, dryRun, simulationSteps) vSimSimulatorFiles = host.PoCConfig['CONFIG.DirectoryNames']['QuestaSimFiles'] self.Directories.Working = host.Directories.Temp / vSimSimulatorFiles self.Directories.PreCompiled = host.Directories.PreCompiled / vSimSimulatorFiles if (SimulationSteps.CleanUpBefore in self._simulationSteps): pass if (SimulationSteps.Prepare in self._simulationSteps): self._PrepareSimulationEnvironment() self._PrepareSimulator()
[docs] def _PrepareSimulator(self): # create the QuestaSim executable factory self.LogVerbose("Preparing Mentor simulator.") # for sectionName in ['INSTALL.Mentor.QuestaSim', 'INSTALL.Mentor.ModelSim', 'INSTALL.Altera.ModelSim']: # if (len(self.Host.PoCConfig.options(sectionName)) != 0): # break # else: # XXX: check SectionName if ModelSim is configured # raise NotConfiguredException( # "Neither Mentor Graphics QuestaSim, ModelSim PE nor ModelSim Altera-Edition are configured on this system.") # questaSection = self.Host.PoCConfig[sectionName] # binaryPath = Path(questaSection['BinaryDirectory']) # version = questaSection['Version'] binaryPath = Path(self.Host.PoCConfig['INSTALL.ModelSim']['BinaryDirectory']) version = self.Host.PoCConfig['INSTALL.ModelSim']['Version'] self._toolChain = QuestaSim(self.Host.Platform, self.DryRun, binaryPath, version, logger=self.Logger)
[docs] def Run(self, testbench, board, vhdlVersion, vhdlGenerics=None): # TODO: refactor into a ModelSim module, shared by QuestaSim and Cocotb (-> MixIn class)? # select modelsim.ini self._modelsimIniPath = self.Directories.PreCompiled if board.Device.Vendor is Vendors.Altera: self._modelsimIniPath /= self.Host.PoCConfig['CONFIG.DirectoryNames']['AlteraSpecificFiles'] elif board.Device.Vendor is Vendors.Lattice: self._modelsimIniPath /= self.Host.PoCConfig['CONFIG.DirectoryNames']['LatticeSpecificFiles'] elif board.Device.Vendor is Vendors.Xilinx: self._modelsimIniPath /= self.Host.PoCConfig['CONFIG.DirectoryNames']['XilinxSpecificFiles'] self._modelsimIniPath /= "modelsim.ini" if not self._modelsimIniPath.exists(): raise SimulatorException("Modelsim ini file '{0!s}' not found.".format(self._modelsimIniPath)) \ from FileNotFoundError(str(self._modelsimIniPath)) super().Run(testbench, board, vhdlVersion, vhdlGenerics)
[docs] def _RunAnalysis(self, _): # create a QuestaVHDLCompiler instance vlib = self._toolChain.GetVHDLLibraryTool() for lib in self._pocProject.VHDLLibraries: vlib.Parameters[vlib.SwitchLibraryName] = lib.Name vlib.CreateLibrary() # create a QuestaVHDLCompiler instance vcom = self._toolChain.GetVHDLCompiler() vcom.Parameters[vcom.FlagQuietMode] = True vcom.Parameters[vcom.FlagExplicit] = True vcom.Parameters[vcom.FlagRangeCheck] = True vcom.Parameters[vcom.SwitchModelSimIniFile] = self._modelsimIniPath.as_posix() vcom.Parameters[vcom.SwitchVHDLVersion] = repr(self._vhdlVersion) recompileScriptContent = dedent("""\ puts "Recompiling..." """) # run vcom compile for each VHDL file for file in self._pocProject.Files(fileType=FileTypes.VHDLSourceFile): if (not file.Path.exists()): raise SimulatorException("Cannot analyse '{0!s}'.".format(file.Path)) from FileNotFoundError(str(file.Path)) vcomLogFile = self.Directories.Working / (file.Path.stem + ".vcom.log") vcom.Parameters[vcom.SwitchVHDLLibrary] = file.LibraryName vcom.Parameters[vcom.ArgLogFile] = vcomLogFile vcom.Parameters[vcom.ArgSourceFile] = file.Path try: vcom.Compile() except QuestaSimException as ex: raise SimulatorException("Error while compiling '{0!s}'.".format(file.Path)) from ex if vcom.HasErrors: raise SkipableSimulatorException("Error while compiling '{0!s}'.".format(file.Path)) # delete empty log files if (vcomLogFile.stat().st_size == 0): try: vcomLogFile.unlink() except OSError as ex: raise SimulatorException("Error while deleting '{0!s}'.".format(vcomLogFile)) from ex # collecting all compile commands in a buffer recompileScriptContent += dedent("""\ puts " Compiling '{file}'..." {tcl} """).format( file=file.Path.as_posix(), tcl=vcom.GetTclCommand() ) recompileScriptContent += dedent("""\ puts "Recompilation done" puts "Restarting simulation..." restart -force puts "Simulation is restarted." """) recompileScriptContent = recompileScriptContent.replace("\\", "/") # WORKAROUND: to convert all paths to Tcl compatible paths. recompileScriptPath = self.Directories.Working / "recompile.do" self.LogDebug("Writing recompile script to '{0!s}'".format(recompileScriptPath)) with recompileScriptPath.open('w') as fileHandle: fileHandle.write(recompileScriptContent)
[docs] def _RunSimulation(self, testbench): if (SimulationSteps.ShowWaveform in self._simulationSteps): return self._RunSimulationWithGUI(testbench) tclBatchFilePath = self.Host.Directories.Root / self.Host.PoCConfig[testbench.ConfigSectionName]['vSimBatchScript'] tclDefaultBatchFilePath = self.Host.Directories.Root / self.Host.PoCConfig[testbench.ConfigSectionName]['vSimDefaultBatchScript'] # create a QuestaSimulator instance vsim = self._toolChain.GetSimulator() vsim.Parameters[vsim.SwitchModelSimIniFile] = self._modelsimIniPath.as_posix() # vsim.Parameters[vsim.FlagOptimization] = True # FIXME: vsim.Parameters[vsim.FlagReportAsError] = "3473" vsim.Parameters[vsim.SwitchTimeResolution] = "1fs" vsim.Parameters[vsim.FlagCommandLineMode] = True vsim.Parameters[vsim.SwitchTopLevel] = "{0}.{1}".format(VHDL_TESTBENCH_LIBRARY_NAME, testbench.ModuleName) # find a Tcl batch script for the BATCH mode vsimBatchCommand = "" if (tclBatchFilePath.exists()): self.LogDebug("Found Tcl script for BATCH mode: '{0!s}'".format(tclBatchFilePath)) vsimBatchCommand += "do {0};".format(tclBatchFilePath.as_posix()) elif (tclDefaultBatchFilePath.exists()): self.LogDebug("Falling back to default Tcl script for BATCH mode: '{0!s}'".format(tclDefaultBatchFilePath)) vsimBatchCommand += "do {0};".format(tclDefaultBatchFilePath.as_posix()) else: raise QuestaSimException("No Tcl batch script for BATCH mode found.") \ from FileNotFoundError(str(tclDefaultBatchFilePath)) vsim.Parameters[vsim.SwitchBatchCommand] = vsimBatchCommand testbench.Result = vsim.Simulate()
[docs] def _RunSimulationWithGUI(self, testbench): tclGUIFilePath = self.Host.Directories.Root / self.Host.PoCConfig[testbench.ConfigSectionName]['vSimGUIScript'] tclWaveFilePath = self.Host.Directories.Root / self.Host.PoCConfig[testbench.ConfigSectionName]['vSimWaveScript'] tclDefaultGUIFilePath = self.Host.Directories.Root / self.Host.PoCConfig[testbench.ConfigSectionName]['vSimDefaultGUIScript'] tclDefaultWaveFilePath = self.Host.Directories.Root / self.Host.PoCConfig[testbench.ConfigSectionName]['vSimDefaultWaveScript'] # create a QuestaSimulator instance vsim = self._toolChain.GetSimulator() vsim.Parameters[vsim.SwitchModelSimIniFile] = self._modelsimIniPath.as_posix() # vsim.Parameters[vsim.FlagOptimization] = True # FIXME: vsim.Parameters[vsim.FlagReportAsError] = "3473" vsim.Parameters[vsim.SwitchTimeResolution] = "1fs" vsim.Parameters[vsim.FlagGuiMode] = True vsim.Parameters[vsim.SwitchTopLevel] = "{0}.{1}".format(VHDL_TESTBENCH_LIBRARY_NAME, testbench.ModuleName) # vsim.Parameters[vsim.SwitchTitle] = testbenchName vsimDefaultWaveCommands = "add wave *" # find a Tcl batch script to load predefined signals in the waveform window vsimBatchCommand = "" self.LogDebug("'{0!s}'\n '{1!s}'".format(tclWaveFilePath, self.Host.Directories.Root)) if (tclWaveFilePath != self.Host.Directories.Root): if (tclWaveFilePath.exists()): self.LogDebug("Found waveform script: '{0!s}'".format(tclWaveFilePath)) vsimBatchCommand = "do {0};".format(tclWaveFilePath.as_posix()) elif (tclDefaultWaveFilePath != self.Host.Directories.Root): if (tclDefaultWaveFilePath.exists()): self.LogDebug("Found default waveform script: '{0!s}'".format(tclDefaultWaveFilePath)) vsimBatchCommand = "do {0};".format(tclDefaultWaveFilePath.as_posix()) else: self.LogDebug("Couldn't find default waveform script: '{0!s}'. Loading default command '{1}'.".format(tclDefaultWaveFilePath, vsimDefaultWaveCommands)) vsimBatchCommand = "{0};".format(vsimDefaultWaveCommands) else: self.LogDebug("Couldn't find waveform script: '{0!s}'. Loading default command '{1}'.".format(tclWaveFilePath, vsimDefaultWaveCommands)) vsim.Parameters[vsim.SwitchBatchCommand] = "{0};".format(vsimDefaultWaveCommands) elif (tclDefaultWaveFilePath != self.Host.Directories.Root): if (tclDefaultWaveFilePath.exists()): self.LogDebug("Falling back to default waveform script: '{0!s}'".format(tclDefaultWaveFilePath)) vsimBatchCommand = "do {0};".format(tclDefaultWaveFilePath.as_posix()) else: self.LogDebug("Couldn't find default waveform script: '{0!s}'. Loading default command '{1}'.".format(tclDefaultWaveFilePath, vsimDefaultWaveCommands)) vsimBatchCommand = "{0};".format(vsimDefaultWaveCommands) else: self.LogWarning("No waveform script specified. Loading default command '{1}'.".format(vsimDefaultWaveCommands)) vsimBatchCommand = "{0};".format(vsimDefaultWaveCommands) # find a Tcl batch script for the GUI mode vsimRunScript = "" if (tclGUIFilePath.exists()): self.LogDebug("Found Tcl script for GUI mode: '{0!s}'".format(tclGUIFilePath)) vsimRunScript = tclGUIFilePath.as_posix() vsimBatchCommand += "do {0};".format(vsimRunScript) elif (tclDefaultGUIFilePath.exists()): self.LogDebug("Falling back to default Tcl script for GUI mode: '{0!s}'".format(tclDefaultGUIFilePath)) vsimRunScript = tclDefaultGUIFilePath.as_posix() vsimBatchCommand += "do {0};".format(vsimRunScript) else: raise QuestaSimException("No Tcl batch script for GUI mode found.") \ from FileNotFoundError(str(tclDefaultGUIFilePath)) vsim.Parameters[vsim.SwitchBatchCommand] = vsimBatchCommand # writing a relaunch file recompileScriptPath = self.Directories.Working / "recompile.do" relaunchScriptPath = self.Directories.Working / "relaunch.do" saveWaveformScriptPath = self.Directories.Working / "saveWaveform.do" relaunchScriptContent = dedent("""\ puts "Loading recompile script '{recompileScript}'..." do {recompileScript} puts "Loading run script '{runScript}'..." do {runScript} """).format( recompileScript=recompileScriptPath.as_posix(), runScript=vsimRunScript ) self.LogDebug("Writing relaunch script to '{0!s}'".format(relaunchScriptPath)) with relaunchScriptPath.open('w') as fileHandle: fileHandle.write(relaunchScriptContent) # writing a saveWaveform file saveWaveformScriptContent = dedent("""\ puts "Saving waveform settings to '{waveformFile}'..." write format wave -window .main_pane.wave.interior.cs.body.pw.wf {waveformFile} """).format( waveformFile=tclWaveFilePath.as_posix() ) self.LogDebug("Writing saveWaveform script to '{0!s}'".format(saveWaveformScriptPath)) with saveWaveformScriptPath.open('w') as fileHandle: fileHandle.write(saveWaveformScriptContent) testbench.Result = vsim.Simulate()