コード例 #1
0
ファイル: modelsim_interface.py プロジェクト: suoto/vunit
    def _create_vsim_process(self):
        """
        Create the vsim process
        """
        ident = threading.current_thread().ident

        with self._lock:
            try:
                vsim_process = self._vsim_processes[ident]
                if vsim_process.is_alive():
                    return vsim_process
            except KeyError:
                pass

            transcript_id = self._transcript_id
            self._transcript_id += 1
            vsim_process = Process([
                join(self._prefix, "vsim"), "-c", "-l",
                join(dirname(self._modelsim_ini),
                     "transcript%i" % transcript_id)])
            self._vsim_processes[ident] = vsim_process

        vsim_process.write("#VUNIT_RETURN\n")
        vsim_process.consume_output(silent_output_consumer)
        return vsim_process
コード例 #2
0
ファイル: modelsim_interface.py プロジェクト: mbeziouch/vunit
    def _create_vsim_process(self):
        """
        Create the vsim process
        """
        ident = threading.current_thread().ident

        with self._lock:
            try:
                vsim_process = self._vsim_processes[ident]
                if vsim_process.is_alive():
                    return vsim_process
            except KeyError:
                pass

            transcript_id = self._transcript_id
            self._transcript_id += 1
            vsim_process = Process([
                join(self._prefix, "vsim"), "-c", "-l",
                join(dirname(self._modelsim_ini),
                     "transcript%i" % transcript_id)
            ])
            self._vsim_processes[ident] = vsim_process

        vsim_process.write("#VUNIT_RETURN\n")
        vsim_process.consume_output(silent_output_consumer)
        return vsim_process
コード例 #3
0
ファイル: modelsim_interface.py プロジェクト: VLSI-EDA/vunit
    def _create_vsim_process(self):
        """
        Create the vsim process
        """
        ident = threading.current_thread().ident

        with self._lock:
            try:
                vsim_process = self._vsim_processes[ident]
                if vsim_process.is_alive():
                    return vsim_process
            except KeyError:
                pass

            transcript_id = self._transcript_id
            self._transcript_id += 1
            vsim_process = Process([join(self._prefix, "vsim"), "-c",
                                    "-l", join(dirname(self._modelsim_ini), "transcript%i" % transcript_id)])
            self._vsim_processes[ident] = vsim_process

        vsim_process.write("#VUNIT_RETURN\n")

        try:
            consumer = SilentOutputConsumer()
            vsim_process.consume_output(consumer)
        except Process.NonZeroExitCode:
            # Print output if background vsim process startup failed
            LOGGER.error("Failed to start re-usable background vsim process")
            print(consumer.output)
            raise

        return vsim_process
コード例 #4
0
class ModelSimInterface:
    def __init__(self, modelsim_ini="modelsim.ini", persistent=False, gui=False):
        self._modelsim_ini = modelsim_ini

        # Workarround for Microsemi 10.3a which does not 
        # respect MODELSIM environment variable when set within .do script
        # Microsemi bug reference id: dvt64978 
        os.environ["MODELSIM"] = self._modelsim_ini

        self._create_modelsim_ini()
        self._vsim_process = None
        self._gui = gui
        assert not (persistent and gui)

        if persistent:
            self._create_vsim_process()

    def _teardown(self):
        if self._vsim_process is not None:
            self._send_command("quit")
            self._vsim_process.terminate()
            self._vsim_process = None


    def __del__(self):
        self._teardown()

    def _create_vsim_process(self):
        """
        Create the vsim process
        """

        self._vsim_process = Process(["vsim", "-c",
                                      "-l", join(dirname(self._modelsim_ini), "transcript")])
        self._vsim_process.write("#VUNIT_RETURN\n")
        self._vsim_process.consume_output(OutputConsumer(silent=True))

    def _create_modelsim_ini(self):
        if not file_exists(self._modelsim_ini):
            proc = Process(args=['vmap', '-c'], cwd=dirname(self._modelsim_ini))
            proc.consume_output(callback=None)

    def compile_project(self, project, vhdl_standard):
        for library in project.get_libraries():
            self.create_library(library.name, library.directory)

        for source_file in project.get_files_in_compile_order():
            print('Compiling ' + source_file.name + ' ...')

            if source_file.file_type == 'vhdl':
                success = self.compile_vhdl_file(source_file.name, source_file.library.name, vhdl_standard)
            elif source_file.file_type == 'verilog':
                success = self.compile_verilog_file(source_file.name, source_file.library.name)
            else:
                raise RuntimeError("Unkown file type: " + source_file.file_type)

            if not success:
                raise CompileError("Failed to compile '%s'" % source_file.name)
            project.update(source_file)

    def compile_vhdl_file(self, source_file_name, library_name, vhdl_standard):
        try:
            proc = Process(['vcom', '-quiet', '-modelsimini', self._modelsim_ini,
                            '-' + vhdl_standard, '-work', library_name, source_file_name])
            proc.consume_output()
        except Process.NonZeroExitCode:
            return False
        return True

    def compile_verilog_file(self, source_file_name, library_name):
        try:
            proc = Process(['vlog', '-sv', '-quiet', '-modelsimini', self._modelsim_ini,
                            '-work', library_name, source_file_name])
            proc.consume_output()
        except Process.NonZeroExitCode:
            return False
        return True


    _vmap_pattern = re.compile('maps to directory (?P<dir>.*?)\.')
    def create_library(self, library_name, path):

        if not file_exists(dirname(path)):
            os.makedirs(dirname(path))

        if not file_exists(path):
            proc = Process(['vlib', '-unix', path])
            proc.consume_output(callback=None)

        try:
            proc = Process(['vmap', '-modelsimini', self._modelsim_ini, library_name])
            proc.consume_output(callback=None)
        except Process.NonZeroExitCode:
            pass

        match = self._vmap_pattern.search(proc.output)
        if match:
            do_vmap = not file_exists(match.group('dir'))
        else:
            do_vmap = False

        if 'No mapping for library' in proc.output:
            do_vmap = True

        if do_vmap:
            proc = Process(['vmap','-modelsimini', self._modelsim_ini, library_name, path])
            proc.consume_output(callback=None)

    def _create_load_function(self, library_name, entity_name, architecture_name, generics, pli, output_path):
        set_generic_str = "".join(('    set vunit_generic_%s {%s}\n' % (name, value) for name, value in generics.items()))
        set_generic_name_str = " ".join(('-g%s="${vunit_generic_%s}"' % (name, name) for name in generics))
        pli_str = " ".join("-pli {%s}" %  fix_path(name) for name in pli)
        if architecture_name is None:
            architecture_suffix = ""
        else:
            architecture_suffix = "(%s)" % architecture_name

        tcl = """
proc vunit_load {{}} {{
    {set_generic_str}

    # Workaround -modelsimini flag not respected in some versions of modelsim
    global env
    set env(MODELSIM) "{modelsimini}"
    vsim -wlf "{wlf_file_name}" -quiet -t ps {pli_str} {set_generic_name_str} {library_name}.{entity_name}{architecture_suffix}
    set no_finished_signal [catch {{examine -internal {{/vunit_finished}}}}]
    set no_test_runner_exit [catch {{examine -internal {{/run_base_pkg/runner.exit_without_errors}}}}]

    if {{${{no_finished_signal}} && ${{no_test_runner_exit}}}}  {{
        echo {{Error: Found none of either simulation shutdown mechanisms}}
        echo {{Error: 1) No vunit_finished signal on test bench top level}}
        echo {{Error: 2) No vunit test runner package used}}
        return 1
    }}
    return 0
}}
""".format(modelsimini=fix_path(self._modelsim_ini),
           pli_str=pli_str,
           set_generic_str=set_generic_str,
           set_generic_name_str=set_generic_name_str,
           library_name=library_name,
           entity_name=entity_name,
           architecture_suffix=architecture_suffix,
           wlf_file_name=fix_path(join(output_path, "vsim.wlf")))

        return tcl

    def _create_run_function(self, fail_on_warning=False):
        return """
proc vunit_run {} {
    global BreakOnAssertion

    # Break on error
    set BreakOnAssertion %i

    proc on_break {} {
        resume
    }
    onbreak {on_break}

    set no_finished_signal [catch {examine -internal {/vunit_finished}}]

    if {${no_finished_signal}} {
        set exit_boolean {/run_base_pkg/runner.exit_without_errors}
    } {
        set exit_boolean {/vunit_finished}
    }

    when -fast "${exit_boolean} = TRUE" {
        echo "Finished"
        stop
        resume
    }

    run -all
    set failed [expr [examine -internal ${exit_boolean}]!=TRUE]
    if {$failed} {
        catch {
            # tb command can fail when error comes from pli
            echo
            echo "Stack trace result from 'tb' command"
            echo [tb]
            echo
            echo "Surrounding code from 'see' command"
            echo [see]
        }
    }
    return $failed
}
""" % (1 if fail_on_warning else 2)


    def _create_common_script(self, library_name, entity_name, architecture_name, generics, pli, fail_on_warning, output_path):
        """
        Create tcl script with functions common to interactive and batch modes
        """
        tcl = """
proc vunit_help {} {
    echo {vunit_help - Prints this help}
    echo {vunit_load - Load design with correct generics for the test}
    echo {vunit_run  - Run test, must do vunit_load first}
}
"""
        tcl += self._create_load_function(library_name, entity_name, architecture_name, generics, pli, output_path)
        tcl += self._create_run_function(fail_on_warning)
        return tcl

    def _create_batch_script(self, common_file_name, load_only=False):
        """
        Create tcl script to run in batch mode
        """
        batch_do = "do " + fix_path(common_file_name) + "\n"
        batch_do += "quietly set failed [vunit_load]\n"
        batch_do += "if {$failed} {quit -f -code 1}\n"
        if not load_only:
            batch_do += "quietly set failed [vunit_run]\n"
            batch_do += "if {$failed} {quit -f -code 1}\n"
        batch_do += "quit -f -code 0\n"
        return batch_do

    def _create_user_script(self, common_file_name):
        tcl = "do %s\n" % fix_path(common_file_name)
        tcl += "vunit_help\n"
        return tcl

    def _run_batch_file(self, batch_file_name, gui=False):
        try:
            args = ['vsim', '-quiet',
                    "-l", join(dirname(batch_file_name), "transcript"),
                    '-do', "do %s" % fix_path(batch_file_name)]
            
            if gui:
                args.append('-gui')
            else:
                args.append('-c')

            proc = Process(args)
            proc.consume_output()
        except Process.NonZeroExitCode:
            return False
        return True

    def _send_command(self, cmd):
        self._vsim_process.write("%s\n" % cmd)
        self._vsim_process._next()
        self._vsim_process.write("#VUNIT_RETURN\n")
        self._vsim_process.consume_output(OutputConsumer())

    def _read_var(self, varname):
        self._vsim_process.write("echo $%s #VUNIT_READVAR\n" % varname)
        self._vsim_process._next()
        self._vsim_process.write("#VUNIT_RETURN\n")
        consumer = OutputConsumer(silent=True)
        self._vsim_process.consume_output(consumer)
        return consumer.var

    def _run_persistent(self, common_file_name, load_only=False):
        try:
            self._send_command("quit -sim")
            self._send_command("do " + fix_path(common_file_name))
            self._send_command("quietly set failed [vunit_load]")
            if self._read_var("failed") == '1':
                return False

            if not load_only:
                self._send_command("quietly set failed [vunit_run]")
                if self._read_var("failed") == '1':
                    return False

            return True
        except Process.NonZeroExitCode:
            self._create_vsim_process()
            return False

    def simulate(self, output_path, library_name, entity_name, architecture_name=None, generics=None, pli=None, load_only=None, fail_on_warning=False):
        generics = {} if generics is None else generics
        pli = [] if pli is None else pli
        msim_output_path = abspath(join(output_path, "msim"))
        common_file_name = join(msim_output_path, "common.do")
        user_file_name = join(msim_output_path, "user.do")
        batch_file_name = join(msim_output_path, "batch.do")

        common_do = self._create_common_script(library_name, entity_name, architecture_name, generics, pli,
                                               fail_on_warning=fail_on_warning,
                                               output_path=msim_output_path)
        user_do = self._create_user_script(common_file_name)
        batch_do = self._create_batch_script(common_file_name, load_only)
        write_file(common_file_name, common_do)
        write_file(user_file_name, user_do)
        write_file(batch_file_name, batch_do)

        if self._gui:
            success = self._run_batch_file(user_file_name, gui=True)
        elif self._vsim_process is None:
            success = self._run_batch_file(batch_file_name)
        else:
            success = self._run_persistent(common_file_name, load_only)

        return success

    def load(self, output_path, library_name, entity_name, architecture_name=None, generics=None, pli=None):
        return self.simulate(output_path, library_name, entity_name, architecture_name, generics, pli, load_only=True)

    def __del__(self):
        if self._vsim_process is not None:
            del self._vsim_process
コード例 #5
0
class ModelSimInterface:
    def __init__(self,
                 modelsim_ini="modelsim.ini",
                 persistent=False,
                 gui=False):
        self._modelsim_ini = modelsim_ini

        # Workarround for Microsemi 10.3a which does not
        # respect MODELSIM environment variable when set within .do script
        # Microsemi bug reference id: dvt64978
        os.environ["MODELSIM"] = self._modelsim_ini

        self._create_modelsim_ini()
        self._vsim_process = None
        self._gui = gui
        assert not (persistent and gui)

        if persistent:
            self._create_vsim_process()

    def _teardown(self):
        if self._vsim_process is not None:
            self._send_command("quit")
            self._vsim_process.terminate()
            self._vsim_process = None

    def __del__(self):
        self._teardown()

    def _create_vsim_process(self):
        """
        Create the vsim process
        """

        self._vsim_process = Process([
            "vsim", "-c", "-l",
            join(dirname(self._modelsim_ini), "transcript")
        ])
        self._vsim_process.write("#VUNIT_RETURN\n")
        self._vsim_process.consume_output(OutputConsumer(silent=True))

    def _create_modelsim_ini(self):
        if not file_exists(self._modelsim_ini):
            proc = Process(args=['vmap', '-c'],
                           cwd=dirname(self._modelsim_ini))
            proc.consume_output(callback=None)

    def compile_project(self, project, vhdl_standard):
        for library in project.get_libraries():
            self.create_library(library.name, library.directory)

        for source_file in project.get_files_in_compile_order():
            print('Compiling ' + source_file.name + ' ...')

            if source_file.file_type == 'vhdl':
                success = self.compile_vhdl_file(source_file.name,
                                                 source_file.library.name,
                                                 vhdl_standard)
            elif source_file.file_type == 'verilog':
                success = self.compile_verilog_file(source_file.name,
                                                    source_file.library.name)
            else:
                raise RuntimeError("Unkown file type: " +
                                   source_file.file_type)

            if not success:
                raise CompileError("Failed to compile '%s'" % source_file.name)
            project.update(source_file)

    def compile_vhdl_file(self, source_file_name, library_name, vhdl_standard):
        try:
            proc = Process([
                'vcom', '-quiet', '-modelsimini', self._modelsim_ini,
                '-' + vhdl_standard, '-work', library_name, source_file_name
            ])
            proc.consume_output()
        except Process.NonZeroExitCode:
            return False
        return True

    def compile_verilog_file(self, source_file_name, library_name):
        try:
            proc = Process([
                'vlog', '-sv', '-quiet', '-modelsimini', self._modelsim_ini,
                '-work', library_name, source_file_name
            ])
            proc.consume_output()
        except Process.NonZeroExitCode:
            return False
        return True

    _vmap_pattern = re.compile('maps to directory (?P<dir>.*?)\.')

    def create_library(self, library_name, path):

        if not file_exists(dirname(path)):
            os.makedirs(dirname(path))

        if not file_exists(path):
            proc = Process(['vlib', '-unix', path])
            proc.consume_output(callback=None)

        try:
            proc = Process(
                ['vmap', '-modelsimini', self._modelsim_ini, library_name])
            proc.consume_output(callback=None)
        except Process.NonZeroExitCode:
            pass

        match = self._vmap_pattern.search(proc.output)
        if match:
            do_vmap = not file_exists(match.group('dir'))
        else:
            do_vmap = False

        if 'No mapping for library' in proc.output:
            do_vmap = True

        if do_vmap:
            proc = Process([
                'vmap', '-modelsimini', self._modelsim_ini, library_name, path
            ])
            proc.consume_output(callback=None)

    def _create_load_function(self, library_name, entity_name,
                              architecture_name, generics, pli, output_path):
        set_generic_str = "".join(
            ('    set vunit_generic_%s {%s}\n' % (name, value)
             for name, value in generics.items()))
        set_generic_name_str = " ".join(
            ('-g%s="${vunit_generic_%s}"' % (name, name) for name in generics))
        pli_str = " ".join("-pli {%s}" % fix_path(name) for name in pli)
        if architecture_name is None:
            architecture_suffix = ""
        else:
            architecture_suffix = "(%s)" % architecture_name

        tcl = """
proc vunit_load {{}} {{
    {set_generic_str}

    # Workaround -modelsimini flag not respected in some versions of modelsim
    global env
    set env(MODELSIM) "{modelsimini}"
    vsim -wlf "{wlf_file_name}" -quiet -t ps {pli_str} {set_generic_name_str} {library_name}.{entity_name}{architecture_suffix}
    set no_finished_signal [catch {{examine -internal {{/vunit_finished}}}}]
    set no_test_runner_exit [catch {{examine -internal {{/run_base_pkg/runner.exit_without_errors}}}}]

    if {{${{no_finished_signal}} && ${{no_test_runner_exit}}}}  {{
        echo {{Error: Found none of either simulation shutdown mechanisms}}
        echo {{Error: 1) No vunit_finished signal on test bench top level}}
        echo {{Error: 2) No vunit test runner package used}}
        return 1
    }}
    return 0
}}
""".format(modelsimini=fix_path(self._modelsim_ini),
           pli_str=pli_str,
           set_generic_str=set_generic_str,
           set_generic_name_str=set_generic_name_str,
           library_name=library_name,
           entity_name=entity_name,
           architecture_suffix=architecture_suffix,
           wlf_file_name=fix_path(join(output_path, "vsim.wlf")))

        return tcl

    def _create_run_function(self, fail_on_warning=False):
        return """
proc vunit_run {} {
    global BreakOnAssertion

    # Break on error
    set BreakOnAssertion %i

    proc on_break {} {
        resume
    }
    onbreak {on_break}

    set no_finished_signal [catch {examine -internal {/vunit_finished}}]

    if {${no_finished_signal}} {
        set exit_boolean {/run_base_pkg/runner.exit_without_errors}
    } {
        set exit_boolean {/vunit_finished}
    }

    when -fast "${exit_boolean} = TRUE" {
        echo "Finished"
        stop
        resume
    }

    run -all
    set failed [expr [examine -internal ${exit_boolean}]!=TRUE]
    if {$failed} {
        catch {
            # tb command can fail when error comes from pli
            echo
            echo "Stack trace result from 'tb' command"
            echo [tb]
            echo
            echo "Surrounding code from 'see' command"
            echo [see]
        }
    }
    return $failed
}
""" % (1 if fail_on_warning else 2)

    def _create_common_script(self, library_name, entity_name,
                              architecture_name, generics, pli,
                              fail_on_warning, output_path):
        """
        Create tcl script with functions common to interactive and batch modes
        """
        tcl = """
proc vunit_help {} {
    echo {vunit_help - Prints this help}
    echo {vunit_load - Load design with correct generics for the test}
    echo {vunit_run  - Run test, must do vunit_load first}
}
"""
        tcl += self._create_load_function(library_name, entity_name,
                                          architecture_name, generics, pli,
                                          output_path)
        tcl += self._create_run_function(fail_on_warning)
        return tcl

    def _create_batch_script(self, common_file_name, load_only=False):
        """
        Create tcl script to run in batch mode
        """
        batch_do = "do " + fix_path(common_file_name) + "\n"
        batch_do += "quietly set failed [vunit_load]\n"
        batch_do += "if {$failed} {quit -f -code 1}\n"
        if not load_only:
            batch_do += "quietly set failed [vunit_run]\n"
            batch_do += "if {$failed} {quit -f -code 1}\n"
        batch_do += "quit -f -code 0\n"
        return batch_do

    def _create_user_script(self, common_file_name):
        tcl = "do %s\n" % fix_path(common_file_name)
        tcl += "vunit_help\n"
        return tcl

    def _run_batch_file(self, batch_file_name, gui=False):
        try:
            args = [
                'vsim', '-quiet', "-l",
                join(dirname(batch_file_name), "transcript"), '-do',
                "do %s" % fix_path(batch_file_name)
            ]

            if gui:
                args.append('-gui')
            else:
                args.append('-c')

            proc = Process(args)
            proc.consume_output()
        except Process.NonZeroExitCode:
            return False
        return True

    def _send_command(self, cmd):
        self._vsim_process.write("%s\n" % cmd)
        self._vsim_process._next()
        self._vsim_process.write("#VUNIT_RETURN\n")
        self._vsim_process.consume_output(OutputConsumer())

    def _read_var(self, varname):
        self._vsim_process.write("echo $%s #VUNIT_READVAR\n" % varname)
        self._vsim_process._next()
        self._vsim_process.write("#VUNIT_RETURN\n")
        consumer = OutputConsumer(silent=True)
        self._vsim_process.consume_output(consumer)
        return consumer.var

    def _run_persistent(self, common_file_name, load_only=False):
        try:
            self._send_command("quit -sim")
            self._send_command("do " + fix_path(common_file_name))
            self._send_command("quietly set failed [vunit_load]")
            if self._read_var("failed") == '1':
                return False

            if not load_only:
                self._send_command("quietly set failed [vunit_run]")
                if self._read_var("failed") == '1':
                    return False

            return True
        except Process.NonZeroExitCode:
            self._create_vsim_process()
            return False

    def simulate(self,
                 output_path,
                 library_name,
                 entity_name,
                 architecture_name=None,
                 generics=None,
                 pli=None,
                 load_only=None,
                 fail_on_warning=False):
        generics = {} if generics is None else generics
        pli = [] if pli is None else pli
        msim_output_path = abspath(join(output_path, "msim"))
        common_file_name = join(msim_output_path, "common.do")
        user_file_name = join(msim_output_path, "user.do")
        batch_file_name = join(msim_output_path, "batch.do")

        common_do = self._create_common_script(library_name,
                                               entity_name,
                                               architecture_name,
                                               generics,
                                               pli,
                                               fail_on_warning=fail_on_warning,
                                               output_path=msim_output_path)
        user_do = self._create_user_script(common_file_name)
        batch_do = self._create_batch_script(common_file_name, load_only)
        write_file(common_file_name, common_do)
        write_file(user_file_name, user_do)
        write_file(batch_file_name, batch_do)

        if self._gui:
            success = self._run_batch_file(user_file_name, gui=True)
        elif self._vsim_process is None:
            success = self._run_batch_file(batch_file_name)
        else:
            success = self._run_persistent(common_file_name, load_only)

        return success

    def load(self,
             output_path,
             library_name,
             entity_name,
             architecture_name=None,
             generics=None,
             pli=None):
        return self.simulate(output_path,
                             library_name,
                             entity_name,
                             architecture_name,
                             generics,
                             pli,
                             load_only=True)

    def __del__(self):
        if self._vsim_process is not None:
            del self._vsim_process