Source code for pyIPCMI.Compiler.XCICompiler

# 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 Module:    Xilinx Vivado IP Catalog synthesizer (compiler) compiles xci IPCores to netlists.
#
# 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 datetime                 import datetime
from os                       import chdir
from pathlib                  import Path
from shutil                   import copy as shutil_copy
from textwrap                 import dedent

from pyIPCMI.Base.Project             import ToolChain, Tool
from pyIPCMI.DataBase.Entity          import WildCard
from pyIPCMI.ToolChain.Xilinx.Vivado  import Vivado, VivadoException
from pyIPCMI.Compiler                 import CompilerException, SkipableCompilerException, CompileState, Compiler as BaseCompiler


__api__ = [
	'Compiler'
]
__all__ = __api__


[docs]class Compiler(BaseCompiler): TOOL_CHAIN = ToolChain.Xilinx_Vivado TOOL = Tool.Xilinx_IPCatalog def __init__(self, host, dryRun, noCleanUp): super().__init__(host, dryRun, noCleanUp) configSection = host.Config['CONFIG.DirectoryNames'] self.Directories.Working = host.Directories.Temp / configSection['VivadoIPCatalogFiles'] self.Directories.Netlist = host.Directories.Root / configSection['NetlistFiles'] self._PrepareCompiler()
[docs] def _PrepareCompiler(self): super()._PrepareCompiler() vivadoSection = self.Host.Config['INSTALL.Xilinx.Vivado'] version = vivadoSection['Version'] installationDirectory = Path(vivadoSection['InstallationDirectory']) binaryPath = Path(vivadoSection['BinaryDirectory']) self._toolChain = Vivado(self.Host.Platform, self.DryRun, binaryPath, version, logger=self.Logger) self._toolChain.PreparseEnvironment(installationDirectory)
[docs] def RunAll(self, fqnList, *args, **kwargs): """Run a list of netlist compilations. Expand wildcards to all selected netlists.""" 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 netlist in entity.GetCoreGenNetlists(): self.TryRun(netlist, *args, **kwargs) else: netlist = entity.CGNetlist self.TryRun(netlist, *args, **kwargs) except KeyboardInterrupt: self.LogError("Received a keyboard interrupt.") finally: self._testSuite.StopTimer() self.PrintOverallCompileReport() return self._testSuite.IsAllSuccess
[docs] def Run(self, netlist, board): super().Run(netlist, board) self._prepareTime = self._GetTimeDeltaSinceLastEvent() self.LogNormal("Executing pre-processing tasks...") self._state = CompileState.PreCopy self._RunPreCopy(netlist) self._state = CompileState.PrePatch self._RunPreReplace(netlist) self._preTasksTime = self._GetTimeDeltaSinceLastEvent() self.LogNormal("Running Xilinx Core Generator...") self._state = CompileState.Compile self._RunCompile(netlist, board.Device) self._compileTime = self._GetTimeDeltaSinceLastEvent() self.LogNormal("Executing post-processing tasks...") self._state = CompileState.PostCopy self._RunPostCopy(netlist) self._state = CompileState.PostPatch self._RunPostReplace(netlist) self._state = CompileState.PostDelete self._RunPostDelete(netlist) self._postTasksTime = self._GetTimeDeltaSinceLastEvent() self._endAt = datetime.now()
[docs] def _WriteSpecialSectionIntoConfig(self, device): # add the key Device to section SPECIAL at runtime to change interpolation results self.Host.Config['SPECIAL'] = {} self.Host.Config['SPECIAL']['Device'] = device.FullName self.Host.Config['SPECIAL']['DeviceSeries'] = device.Series self.Host.Config['SPECIAL']['OutputDir'] = self.Directories.Working.as_posix()
[docs] def _RunCompile(self, netlist, device): self.LogVerbose("Patching coregen.cgp and .cgc files...") # read netlist settings from configuration file xciInputFilePath = netlist.XciFile cgcTemplateFilePath = self.Directories.Netlist / "template.cgc" cgpFilePath = self.Directories.Working / "coregen.cgp" cgcFilePath = self.Directories.Working / "coregen.cgc" xciFilePath = self.Directories.Working / xciInputFilePath.name if (self.Host.Platform == "Windows"): WorkingDirectory = ".\\temp\\" else: WorkingDirectory = "./temp/" # write CoreGenerator project file cgProjectFileContent = dedent("""\ SET addpads = false SET asysymbol = false SET busformat = BusFormatAngleBracketNotRipped SET createndf = false SET designentry = VHDL SET device = {Device} SET devicefamily = {DeviceFamily} SET flowvendor = Other SET formalverification = false SET foundationsym = false SET implementationfiletype = Ngc SET package = {Package} SET removerpms = false SET simulationfiles = Behavioral SET speedgrade = {SpeedGrade} SET verilogsim = false SET vhdlsim = true SET workingdirectory = {WorkingDirectory} """.format( Device=device.ShortName.lower(), DeviceFamily=device.FamilyName.lower(), Package=(str(device.Package).lower() + str(device.PinCount)), SpeedGrade=device.SpeedGrade, WorkingDirectory=WorkingDirectory )) self.LogDebug("Writing CoreGen project file to '{0}'.".format(cgpFilePath)) with cgpFilePath.open('w') as cgpFileHandle: cgpFileHandle.write(cgProjectFileContent) # write CoreGenerator content? file self.LogDebug("Reading CoreGen content file to '{0}'.".format(cgcTemplateFilePath)) with cgcTemplateFilePath.open('r') as cgcFileHandle: cgContentFileContent = cgcFileHandle.read() cgContentFileContent = cgContentFileContent.format( name="lcd_ChipScopeVIO", device=device.ShortName, devicefamily=device.FamilyName, package=(str(device.Package) + str(device.PinCount)), speedgrade=device.SpeedGrade ) self.LogDebug("Writing CoreGen content file to '{0}'.".format(cgcFilePath)) with cgcFilePath.open('w') as cgcFileHandle: cgcFileHandle.write(cgContentFileContent) # copy xci file into temporary directory self.LogVerbose("Copy CoreGen xci file to '{0}'.".format(xciFilePath)) self.LogDebug("cp {0!s} {1!s}".format(xciInputFilePath, self.Directories.Working)) try: shutil_copy(str(xciInputFilePath), str(xciFilePath)) except OSError as ex: raise CompilerException("Error while copying '{0!s}'.".format(xciInputFilePath)) from ex # change working directory to temporary CoreGen path self.LogDebug("cd {0!s}".format(self.Directories.Working)) try: chdir(str(self.Directories.Working)) except OSError as ex: raise CompilerException("Error while changing to '{0!s}'.".format(self.Directories.Working)) from ex # running CoreGen # ========================================================================== self.LogVerbose("Executing CoreGen...") coreGen = self._toolChain.GetCoreGenerator() coreGen.Parameters[coreGen.SwitchProjectFile] = "." # use current directory and the default project name coreGen.Parameters[coreGen.SwitchBatchFile] = str(xciFilePath) coreGen.Parameters[coreGen.FlagRegenerate] = True try: coreGen.Generate() except VivadoException as ex: raise CompilerException("Error while compiling '{0!s}'.".format(netlist)) from ex if coreGen.HasErrors: raise SkipableCompilerException("Error while compiling '{0!s}'.".format(netlist))
[docs] def _WriteTclFile(self, netlist, device): buffer = dedent("""\ create_project -in_memory -part {part} set_param synth.vivado.isSynthRun true set_property target_language VHDL [current_project] read_ip -quiet {xciFile}go synth_design -top {ipCoreName} -part {part} -mode out_of_context write_checkpoint -noxdef {top}.dcp if { [catch { report_utilization -file {top}_synth.rpt -pb {top}_synth.pb } _RESULT ] } { puts "CRITICAL WARNING: Error reported: $_RESULT" } if { [catch { write_verilog -force -mode synth_stub {xciFilebaseName}_stub.v } _RESULT ] } { puts "CRITICAL WARNING: Unable to successfully create a Verilog synthesis stub for the sub-design. Error reported: $_RESULT" } if { [catch { write_vhdl -force -mode synth_stub {xciFilebaseName}_stub.vhdl } _RESULT ] } { puts "CRITICAL WARNING: Unable to successfully create a VHDL synthesis stub for the sub-design. Error reported: $_RESULT" } if { [catch { write_verilog -force -mode funcsim {xciFilebaseName}_sim_netlist.v } _RESULT ] } { puts "CRITICAL WARNING: Unable to successfully create the Verilog functional simulation sub-design file. Error reported: $_RESULT" } if { [catch { write_vhdl -force -mode funcsim {xciFilebaseName}_sim_netlist.vhdl } _RESULT ] } { puts "CRITICAL WARNING: Unable to successfully create the VHDL functional simulation sub-design file. Error reported: $_RESULT" } """).format( part=device.FullName2, xciFile=xciFile.as_posix(), xciFilebaseName=xciFile.BaseName, top=netlist.ModuleName, ipCoreName="foo.xci" ) self.LogDebug("Writing Vivado TCL file to '{0!s}'".format(netlist.TclFile)) with netlist.TclFile.open('w') as tclFileHandle: tclFileHandle.write(buffer)