Source code for Simulator

# 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
#
# Python Sub Module:    TODO:
#
# 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 datetime           import datetime
from enum               import Enum, unique

from flags              import Flags

from Base               import IHost
from Base.Exceptions    import ExceptionBase, SkipableException
from Base.Logging       import LogEntry
from Base.Project       import Environment, VHDLVersion
from Base.Shared        import Shared, to_time
from DataBase.Entity    import WildCard, SimulationResult
from DataBase.TestCase  import TestCase, SimulationStatus, TestSuite
from lib.Decorators     import MethodAlias
from lib.Functions      import Init
from lib.SphinxExtensions import DocumentMemberAttribute


__api__ = [
	'SimulatorException',
	'SkipableSimulatorException',
	'PoCSimulationResultNotFoundException',
	'SimulationSteps',
	'SimulationState',
	'SimulationResult',
	'Simulator',
	'PoCSimulationResultFilter'
]
__all__ = __api__


VHDL_TESTBENCH_LIBRARY_NAME = "test"


[docs]class SimulatorException(ExceptionBase): """Base class for all SimulatorException classes. It is raised while running simulation tasks in PoC. """
[docs]class SkipableSimulatorException(SimulatorException, SkipableException): """``SkipableSimulatorException`` is a :py:exc:`SimulatorException`, which can be skipped. """
[docs]class PoCSimulationResultNotFoundException(SkipableSimulatorException): """This exception is raised if the expected PoC simulation result string was not found in the simulator's output. """
@unique
[docs]class SimulationSteps(Flags): """Simulation step enumeration.""" Prepare = 1 << 0 CleanUpBefore = 1 << 1 CleanUpAfter = 1 << 2 Analyze = 1 << 5 Elaborate = 1 << 6 # Compile = 1 << 7 # Optimize = 1 << 8 Simulate = 1 << 9 ShowWaveform = 1 << 10 ShowCoverage = 1 << 11 ShowReport = 1 << 15 Recompile = 1 << 25 Resimulate = 1 << 26 # Review = 1 << 27 def __and__(self, other): if isinstance(other, bool): return self if other else self.__class__.no_flags else: return super().__and__(other)
@unique
[docs]class SimulationState(Enum): """Simulation state enumeration.""" Prepare = 0 Analyze = 1 Elaborate = 2 Optimize = 3 Simulate = 4 View = 5 Coverage = 6
[docs]class Simulator(Shared): """Base class for all Simulator classes.""" ENVIRONMENT = Environment.Simulation VHDL_VERSION = VHDLVersion.VHDL2008 class __Directories__(Shared.__Directories__): PreCompiled = None @DocumentMemberAttribute()
[docs] def __init__(self, host : IHost, dryRun, simulationSteps : SimulationSteps): """Class initializer :type host: object :param host: The hosting instance for this instance. :type dryRun: bool :param dryRun: Enable dry-run mode :type simulationSteps: SimulationSteps :param simulationSteps: A set of simulation step to precess. """ super().__init__(host, dryRun) self._vhdlVersion = None self._vhdlGenerics = None self._toolChain = None self._simulationSteps = simulationSteps self._testSuite = TestSuite() # TODO: This includes not the read ini files phases ... self._state = SimulationState.Prepare self._analyzeTime = None self._elaborationTime = None self._simulationTime = None
# class properties # ============================================================================ @property def TestSuite(self): return self._testSuite
[docs] def _PrepareSimulationEnvironment(self): self.LogNormal("Preparing simulation environment...") self._PrepareEnvironment()
[docs] def _PrepareEnvironment_PurgeDirectory(self): if (SimulationSteps.CleanUpBefore in self._simulationSteps): super()._PrepareEnvironment_PurgeDirectory()
@MethodAlias(Shared._Prepare) def _PrepareSimulator(self): pass
[docs] def RunAll(self, fqnList, *args, **kwargs): """Run a list of testbenches. Expand wildcards to all selected testbenches.""" self._testSuite.StartTimer() self.Logger.BaseIndent = int(len(fqnList) > 1) try: for fqn in fqnList: entity = fqn.Entity if (isinstance(entity, WildCard)): self.Logger.BaseIndent = 1 for testbench in entity.GetVHDLTestbenches(): self.TryRun(testbench, *args, **kwargs) else: testbench = entity.VHDLTestbench self.TryRun(testbench, *args, **kwargs) except KeyboardInterrupt: self.LogError("Received a keyboard interrupt.") finally: self._testSuite.StopTimer() if (SimulationSteps.ShowReport in self._simulationSteps): self.PrintOverallSimulationReport() return self._testSuite.IsAllPassed
[docs] def TryRun(self, testbench, *args, **kwargs): """Try to run a testbench. Skip skipable exceptions by printing the error and its cause.""" __SIMULATION_STATE_TO_TESTCASE_STATUS__ = { SimulationState.Prepare: SimulationStatus.InternalError, SimulationState.Analyze: SimulationStatus.AnalyzeError, SimulationState.Elaborate: SimulationStatus.ElaborationError, # SimulationState.Optimize: SimulationStatus.ElaborationError, SimulationState.Simulate: SimulationStatus.SimulationError } testCase = TestCase(testbench) self._testSuite.AddTestCase(testCase) testCase.StartTimer() try: self.Run(testbench, *args, **kwargs) testCase.UpdateStatus(testbench.Result) except SkipableSimulatorException as ex: testCase.Status = __SIMULATION_STATE_TO_TESTCASE_STATUS__[self._state] self.LogQuiet(" {RED}ERROR:{NOCOLOR} {ExMsg}".format(ExMsg=ex.message, **Init.Foreground)) cause = ex.__cause__ if (cause is not None): self.LogQuiet(" {YELLOW}{ExType}:{NOCOLOR} {ExMsg!s}".format(ExType=cause.__class__.__name__, ExMsg=cause, **Init.Foreground)) cause = cause.__cause__ if (cause is not None): self.LogQuiet(" {YELLOW}{ExType}:{NOCOLOR} {ExMsg!s}".format(ExType=cause.__class__.__name__, ExMsg=cause, **Init.Foreground)) self.LogQuiet(" {RED}[SKIPPED DUE TO ERRORS]{NOCOLOR}".format(**Init.Foreground)) except SimulatorException: testCase.Status = __SIMULATION_STATE_TO_TESTCASE_STATUS__[self._state] raise except ExceptionBase: testCase.Status = SimulationStatus.SystemError raise finally: testCase.StopTimer()
[docs] def Run(self, testbench, board, vhdlVersion, vhdlGenerics=None): """Write the Testbench message line, create a PoCProject and add the first *.files file to it.""" self.LogQuiet("{CYAN}Testbench: {0!s}{NOCOLOR}".format(testbench.Parent, **Init.Foreground)) self._vhdlVersion = vhdlVersion self._vhdlGenerics = vhdlGenerics # setup all needed paths to execute fuse self._CreatePoCProject(testbench.ModuleName, board) self._AddFileListFile(testbench.FilesFile) self._prepareTime = self._GetTimeDeltaSinceLastEvent() if self._simulationSteps.CleanUpBefore: pass if self._simulationSteps.Prepare: pass if self._simulationSteps.Analyze: self.LogNormal("Running analysis for every vhdl file...") self._state = SimulationState.Analyze self._RunAnalysis(testbench) self._analyzeTime = self._GetTimeDeltaSinceLastEvent() if self._simulationSteps.Elaborate: self.LogNormal("Running elaboration...") self._state = SimulationState.Elaborate self._RunElaboration(testbench) self._elaborationTime = self._GetTimeDeltaSinceLastEvent() # if self._simulationSteps.Optimize: # pass if self._simulationSteps.Simulate: self.LogNormal("Running simulation...") self._state = SimulationState.Simulate self._RunSimulation(testbench) self._simulationTime = self._GetTimeDeltaSinceLastEvent() if self._simulationSteps.ShowWaveform: self.LogNormal("Executing waveform viewer...") self._state = SimulationState.View self._RunView(testbench) if self._simulationSteps.ShowCoverage: self.LogNormal("Executing coverage analysis...") self._state = SimulationState.View self._RunCoverage(testbench) self._endAt = datetime.now()
[docs] def _RunAnalysis(self, testbench): pass
[docs] def _RunElaboration(self, testbench): pass
[docs] def _RunSimulation(self, testbench): pass
[docs] def _RunView(self, testbench): pass
[docs] def _RunCoverage(self, testbench): pass
[docs] def PrintOverallSimulationReport(self): self.LogQuiet("{HEADLINE}{line}{NOCOLOR}".format(line="=" * 80, **Init.Foreground)) self.LogQuiet("{HEADLINE}{headline: ^80s}{NOCOLOR}".format(headline="Overall Simulation Report", **Init.Foreground)) self.LogQuiet("{HEADLINE}{line}{NOCOLOR}".format(line="=" * 80, **Init.Foreground)) # table header self.LogQuiet("{Name: <24} | {Duration: >5} | {Status: ^11}".format(Name="Name", Duration="Time", Status="Status")) self.LogQuiet("-" * 80) self.PrintSimulationReportLine(self._testSuite, 0, 24) self.LogQuiet("{HEADLINE}{line}{NOCOLOR}".format(line="=" * 80, **Init.Foreground)) self.LogQuiet("Time: {time: >5} Count: {count: <3} Passed: {passed: <3} No Asserts: {noassert: <2} Failed: {failed: <2} Errors: {error: <2}".format( time=to_time(self._testSuite.OverallRunTime), count=self._testSuite.Count, passed=self._testSuite.PassedCount, noassert=self._testSuite.NoAssertsCount, failed=self._testSuite.FailedCount, error=self._testSuite.ErrorCount )) self.LogQuiet("{HEADLINE}{line}{NOCOLOR}".format(line="=" * 80, **Init.Foreground))
__SIMULATION_REPORT_COLOR_TABLE__ = { SimulationStatus.Unknown: "RED", SimulationStatus.DryRun: "YELLOW", SimulationStatus.InternalError: "DARK_RED", SimulationStatus.SystemError: "DARK_RED", SimulationStatus.AnalyzeError: "DARK_RED", SimulationStatus.ElaborationError: "DARK_RED", SimulationStatus.SimulationError: "RED", SimulationStatus.SimulationFailed: "RED", SimulationStatus.SimulationNoAsserts: "YELLOW", SimulationStatus.SimulationSuccess: "GREEN", SimulationStatus.SimulationGUIRun: "YELLOW" } __SIMULATION_REPORT_STATUS_TEXT_TABLE__ = { SimulationStatus.Unknown: "-- ?? --", SimulationStatus.DryRun: "DRY RUN", SimulationStatus.InternalError: "INT. ERROR", SimulationStatus.SystemError: "SYS. ERROR", SimulationStatus.AnalyzeError: "ANA. ERROR", SimulationStatus.ElaborationError: "ELAB. ERROR", SimulationStatus.SimulationError: "SIM. ERROR", SimulationStatus.SimulationFailed: "FAILED", SimulationStatus.SimulationNoAsserts: "NO ASSERTS", SimulationStatus.SimulationSuccess: "PASSED", SimulationStatus.SimulationGUIRun: "GUI RUN" }
[docs] def PrintSimulationReportLine(self, testObject, indent, nameColumnWidth): _indent = " " * indent for group in testObject.Groups.values(): pattern = "{indent}{{groupName: <{nameColumnWidth}}} | | ".format(indent=_indent, nameColumnWidth=nameColumnWidth) self.LogQuiet(pattern.format(groupName=group.Name)) self.PrintSimulationReportLine(group, indent + 1, nameColumnWidth - 2) for testCase in testObject.TestCases.values(): pattern = "{indent}{{testcaseName: <{nameColumnWidth}}} | {{duration: >5}} | {{{color}}}{{status: ^11}}{{NOCOLOR}}".format( indent=_indent, nameColumnWidth=nameColumnWidth, color=self.__SIMULATION_REPORT_COLOR_TABLE__[testCase.Status]) self.LogQuiet(pattern.format(testcaseName=testCase.Name, duration=to_time(testCase.OverallRunTime), status=self.__SIMULATION_REPORT_STATUS_TEXT_TABLE__[testCase.Status], **Init.Foreground))
[docs]def PoCSimulationResultFilter(gen, simulationResult): state = 0 for line in gen: if ((state == 0) and (line.Message == "========================================")): state += 1 elif ((state == 1) and (line.Message == "POC TESTBENCH REPORT")): state += 1 elif ((state == 2) and (line.Message == "========================================")): state += 1 elif ((state == 3) and (line.Message == "========================================")): state += 1 elif ((state == 4) and line.Message.startswith("SIMULATION RESULT = ")): state += 1 if line.Message.endswith("FAILED"): color = Init.Foreground['RED'] simulationResult <<= SimulationResult.Failed elif line.Message.endswith("NO ASSERTS"): color = Init.Foreground['YELLOW'] simulationResult <<= SimulationResult.NoAsserts elif line.Message.endswith("PASSED"): color = Init.Foreground['GREEN'] simulationResult <<= SimulationResult.Passed else: color = Init.Foreground['RED'] simulationResult <<= SimulationResult.Error yield LogEntry("{COLOR}{line}{NOCOLOR}".format(COLOR=color,line=line.Message, **Init.Foreground), line.Severity, line.Indent) continue elif ((state == 5) and (line.Message == "========================================")): state += 1 yield line if (state != 6): raise PoCSimulationResultNotFoundException("No PoC Testbench Report in simulator output found.")