Skip to content
Snippets Groups Projects
srcfile.py 15.1 KiB
Newer Older
Pawel Szostek's avatar
Pawel Szostek committed
# Copyright (c) 2013 CERN
# Author: Pawel Szostek (pawel.szostek@cern.ch)
Paweł Szostek's avatar
Paweł Szostek committed
#
# This file is part of Hdlmake.
#
# Hdlmake is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Hdlmake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Hdlmake.  If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import print_function
from dependable_file import DependableFile
from tools import ise
from tools import modelsim
from tools import quartus
from util import path as path_mod

    def __init__(self, path, module=None):
        self.path = path
        if module is None:
            self.module = global_mod.top_module
        else:
            assert not isinstance(module, basestring)
            self.module = module

    @property
    def name(self):
        return os.path.basename(self.path)

    @property
    def purename(self):
        return os.path.splitext(self.name)[0]

    @property
    def dirname(self):
        return os.path.dirname(self.path)
    def rel_path(self, dir=None):
        if dir is None:
            dir = os.getcwd()
        return path_mod.relpath(self.path, dir)

    def __str__(self):
        return self.path

    def __eq__(self, other):
        _NOTFOUND = object()
        v1, v2 = [getattr(obj, "path", _NOTFOUND) for obj in [self, other]]
        if v1 is _NOTFOUND or v2 is _NOTFOUND:
            return False
        elif v1 != v2:
            return False
        return True

    def __hash__(self):
        return hash(self.path)

    def __cmp__(self, other):
        if self.path < other.path:
            return -1
        if self.path == other.path:
            return 0
        if self.path > other.path:
            return 1

    def __ne__(self, other):
        return not self.__eq__(other)

    def isdir(self):
        return os.path.isdir(self.path)

    def show(self):

    def extension(self):
        tmp = self.path.rsplit('.')
        ext = tmp[len(tmp)-1]
        return ext
class SourceFile(DependableFile, File):
    cur_index = 0
    def __init__(self, path, module, library=None):
        DependableFile.__init__(self)
        File.__init__(self, path=path, module=module)
        if not library:
            library = "work"
        self.library = library
    def gen_index(self):
        self.__class__.cur_index = self.__class__.cur_index+1
        return self.__class__.cur_index
    def __init__(self, path, module, library=None, vcom_opt=None):
        SourceFile.__init__(self, path=path, module=module, library=library)
        if not vcom_opt:
            self.vcom_opt = ""
        else:
            self.vcom_opt = vcom_opt
    def _check_encryption(self):
        f = open(self.path, "rb")
        s = f.read(3)
        f.close()
        if(s == b'Xlx'):
            return True
        else:
            return False

    def _create_deps_provides(self):
        if self._check_encryption():
            self.dep_index = SourceFile.gen_index(self)
        else:
            self.dep_provides = list(self._search_packages())
        logging.debug(self.path + " provides " + str(self.dep_provides))

    def _create_deps_requires(self):
        if self._check_encryption():
            self.dep_index = SourceFile.gen_index(self)
        else:
            self.dep_requires = list(self._search_use_clauses())
        logging.debug(self.path + " provides " + str(self.dep_provides))
    def _search_use_clauses(self):
        """
        Reads a file and looks for 'use' clause. For every 'use' with
        non-standard library a tuple (lib, file) is returned in a list.

        """
        # Modification here! global_mod.top_module.action does not
        # get set for top module in time. FIX this

        std_libs = ['std', 'ieee']
        if global_mod.top_module.action == "simulation":
            try:
                if global_mod.top_module.sim_tool == "isim":
                    std_libs = ise.XilinxsiminiReader().get_libraries()
Paweł Szostek's avatar
Paweł Szostek committed
                elif global_mod.top_module.sim_tool == "vsim" or global_mod.top_module.sim_tool == "modelsim":
                    std_libs = modelsim.ModelsiminiReader().get_libraries()
                elif global_mod.top_module.sim_tool == "iverilog":
                    std_libs = modelsim.MODELSIM_STANDARD_LIBS
                    logging.warning("Could not determine simulation tool. Defaulting to Modelsim")
                    std_libs = modelsim.MODELSIM_STANDARD_LIBS
                logging.error("I/O error: ({0})".format(e.message))
                logging.error("Picking standard Modelsim simulation libraries. Try to fix the error.")
                std_libs = modelsim.MODELSIM_STARDAND_LIBS
        elif global_mod.top_module.action == "synthesis":
            if global_mod.top_module.target == "xilinx":
                std_libs = ise.ISE_STANDARD_LIBS
            elif global_mod.top_module.target == "altera":
                std_libs = quartus.QUARTUS_STANDARD_LIBS

        import re
        try:
            f = open(self.path, "r")
            text = f.readlines()
        except UnicodeDecodeError:
            return []

        use_pattern = re.compile("^[ \t]*use[ \t]+([^; ]+)[ \t]*;.*$")
        lib_pattern = re.compile("([^.]+)\.([^.]+)\.all")

        use_lines = []
        for line in text:
            #identifiers and keywords are case-insensitive in VHDL
            line_lower = line.lower()
            m = re.match(use_pattern, line_lower)
                use_lines.append(m.group(1))

        for line in use_lines:
            m = re.match(lib_pattern, line)
            if m is not None:
                #omit standard libraries
                if (m.group(1)).lower() in std_libs:
                    continue
                if self.library != "work":
                    #if a file is put in a library, `work' points this library
                    new = (self.library.lower(), m.group(2).lower())
                    new = (m.group(1).lower(), m.group(2).lower())
                #dont add if the tuple is already in the list
                if new in self.dep_provides:
                    continue
                ret.add(new)

        f.close()
        return ret

    def _search_packages(self):
        """
        Reads a file and looks for package clase. Returns list of packages' names
        from the file
        """
        import re
        f = open(self.path, "r")
        try:
            text = f.readlines()
        except UnicodeDecodeError:
            return []

        package_pattern = re.compile("^[ \t]*package[ \t]+([^ \t]+)[ \t]+is[ \t]*.*$")
        for line in text:
            #identifiers and keywords are case-insensitive in VHDL
            line = line.lower()
            m = re.match(package_pattern, line)
            if m is not None:
                ret.add((self.library.lower(), m.group(1).lower()))

        f.close()
        return ret
class VerilogFile(SourceFile):
    def __init__(self, path, module, library=None, vlog_opt=None, include_dirs=None):
        if not library:
            library = "work"
        SourceFile.__init__(self, path=path, module=module, library=library)
        if not vlog_opt:
            self.vlog_opt = ""
        else:
            self.vlog_opt = vlog_opt
        self.include_dirs = []
        if include_dirs:
            self.include_dirs.extend(include_dirs)
        self.include_dirs.append(path_mod.relpath(self.dirname))

    def _create_deps_provides(self):
#        self.dep_requires = self.__search_includes()
#        self.dep_provides = self.name
        self.dep_provides = self.name

    def _create_deps_requires(self):
#        self.dep_requires = self.__search_includes()
#        self.dep_provides = self.name
        if global_mod.top_module.sim_tool == "iverilog":
            deps = self._get_iverilog_dependencies()
            self.dep_requires = deps
        else:
            self.dep_requires = self._search_includes()
    def _get_iverilog_dependencies(self):
           #TODO: Check to see dependencies.list doesn't exist already
        if self.path.endswith(".vh") and global_mod.top_module.sim_tool == "iverilog":
            return []
        inc_dirs = []
        #inc_dirs = global_mod.top_module.include_dirs
        inc_dirs = self.include_dirs
        if global_mod.mod_pool:
            inc_dirs.extend([os.path.relpath(m.path) for m in global_mod.mod_pool])
        inc_dirs = list(set(inc_dirs))
        vlog_opt = global_mod.top_module.vlog_opt
        depFileName = "dependencies.list"
        command = "iverilog -DSIMULATE -Wno-timescale -t null -M" + depFileName
        command += "".join(map(lambda x: " -y"+x, inc_dirs))
        command += "".join(map(lambda x: " -I"+x, inc_dirs))
        # TODO: Have to find a way to handle this cleanly
        if self.rel_path().find("config_romx_llrf4") > -1:
            command += " " + vlog_opt
        else:
            command += " " + vlog_opt + " " + self.rel_path()
            logging.debug("running %s" % command)
            retcode = os.system(command)
            # iverilog_cmd = Popen(command, shell=True, stdin=PIPE,
            #                      stdout=PIPE, close_fds=True)
            # iverilog_cmd.stdout.readlines()
            # iverilog_cmd.wait()
            # retcode = iverilog_cmd.returncode
            print("retcode", retcode)

        if retcode and retcode != 256:
Paweł Szostek's avatar
Paweł Szostek committed
            logging.error("Dependencies not met for %s" % str(self.path))
            logging.debug(command, self.include_dirs, inc_dirs, global_mod.mod_pool)
            quit()
        elif retcode == 256:
Paweł Szostek's avatar
Paweł Szostek committed
            #dependencies met
            pass
        depFile = open(depFileName, "r")
        depFiles = list(set([l.strip() for l in depFile.readlines()]))
        depFile.close()
        return depFiles
    def _search_includes(self):
        import re
        f = open(self.path, "r")
        try:
            text = f.readlines()
        except UnicodeDecodeError:
            return []
        include_pattern = re.compile("^[ \t]*`include[ \t]+\"([^ \"]+)\".*$")
        ret = []
        for line in text:
            #in Verilog and SV identifiers are case-sensitive
            m = re.match(include_pattern, line)
            if m is not None:
                ret.append(m.group(1))
        f.close()
        return ret

class QIPFile(File):
# class NGCFile(SourceFile):
#     def __init__(self, path, module):
#         SourceFile.__init__(self, path=path, module=module)
class NGCFile(File):
    pass
    def __init__(self):
        super(SourceFileSet, self).__init__()
        self = []

    def __str__(self):
        return str([str(f) for f in self])

    def add(self, files):
        if isinstance(files, str):
            raise RuntimeError("Expected object, not a string")
        elif files is None:
            logging.debug("Got None as a file.\n Ommiting")
        else:
            try:
                for f in files:
                    if f not in self:
                        self.append(f)
            except:  # single file, not a list
                if files not in self:
                    self.append(files)

    def filter(self, type):
        out = SourceFileSet()
        for f in self:
            if isinstance(f, type):
                out.add(f)
        return out
    def inversed_filter(self, type):
        out = SourceFileSet()
        for f in self:
            if not isinstance(f, type):
                out.add(f)
        return out

    def get_libs(self):
        ret = set()
        for file in self:
            try:
                ret.add(file.library)
            except:
                pass
        return ret
    def new(self, path, module, library=None, vcom_opt=None, vlog_opt=None, include_dirs=None):
        if path =="/home/pawel/cern/wr-cores/testbench/top_level/gn4124_bfm.svh":
            raise Exception()
            raise RuntimeError("Expected a file path, got: "+str(path))
        if not os.path.isabs(path):
            path = os.path.abspath(path)
        tmp = path.rsplit('.')
        extension = tmp[len(tmp)-1]
        logging.debug("add file " + path)

        nf = None
        if extension == 'vhd' or extension == 'vhdl' or extension == 'vho':
            nf = VHDLFile(path=path,
                          module=module,
                          library=library,
                          vcom_opt=vcom_opt)
        elif extension == 'v' or extension == 'vh' or extension == 'vo' or extension == 'vm':
            nf = VerilogFile(path=path,
                             module=module,
                             library=library,
                             vlog_opt=vlog_opt,
                             include_dirs=include_dirs)
        elif extension == 'sv' or extension == 'svh':
            nf = SVFile(path=path, 
                        module=module,
                        library=library,
                        vlog_opt=vlog_opt,
                        include_dirs=include_dirs)
        elif extension == 'ngc':
            nf = NGCFile(path=path, module=module)
        elif extension == 'ucf':
            nf = UCFFile(path=path, module=module)
        elif extension == 'cdc':
            nf = CDCFile(path=path, module=module)
        elif extension == 'wb':
            nf = WBGenFile(path=path, module=module)
        elif extension == 'tcl':
            nf = TCLFile(path=path, module=module)
        elif extension == 'xise' or extension == 'ise':
            nf = XISEFile(path=path, module=module)
        elif extension == 'stp':
            nf = SignalTapFile(path=path, module=module)
        elif extension == 'sdc':
            nf = SDCFile(path=path, module=module)
        elif extension == 'qip':
            nf = QIPFile(path=path, module=module)
        elif extension == 'dpf':
            nf = DPFFile(path=path, module=module)