Source code for pynq.lib.pynqmicroblaze.compile

#   Copyright (c) 2016, Xilinx, Inc.
#   All rights reserved.
#
#   Redistribution and use in source and binary forms, with or without
#   modification, are permitted provided that the following conditions are met:
#
#   1.  Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#
#   2.  Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#
#   3.  Neither the name of the copyright holder nor the names of its
#       contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
#
#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#   OR BUSINESS INTERRUPTION). HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


from os import path
import tempfile
import shutil
from subprocess import run, PIPE, Popen
from pynq import PL
from . import PynqMicroblaze
from . import BSPs
from . import Modules
from .streams import InterruptMBStream


__author__ = "Peter Ogden"
__copyright__ = "Copyright 2017, Xilinx"
__email__ = "ogden@xilinx.com"


[docs]def dependencies(source, bsp): args = ['mb-cpp', '-MM', '-D__attribute__(x)=', '-D__extension__=', '-D__asm__(x)='] for include_path in bsp.include_path: args.append('-I') args.append(include_path) paths = {} for name, module in Modules.items(): for include_path in module.include_path: args.append('-I') args.append(include_path) paths[include_path] = name source = source.replace('__extension__', '') result = run(args, stdout=PIPE, stderr=PIPE, input=source.encode()) if result.returncode: raise RuntimeError("Preprocessor failed: \n" + result.stderr.decode()) dependent_paths = result.stdout.decode() dependent_modules = {v for k, v in paths.items() if dependent_paths.find(k) != -1} return [Modules[k] for k in dependent_modules]
def _find_bsp(cell_name): target_bsp = "bsp_" + cell_name.replace('/', '_') matches = [bsp for bsp in BSPs.keys() if target_bsp.startswith(bsp)] if matches: return BSPs[max(matches, key=len)] raise RuntimeError("BSP not found for " + cell_name)
[docs]def preprocess(source, bsp=None, mb_info=None): if bsp is None: if hasattr(mb_info, 'mb_info'): mb_info = mb_info.mb_info if mb_info is None: raise RuntimeError("Must provide either a BSP or mb_info") bsp = _find_bsp(mb_info['name']) args = ['mb-cpp', '-D__attribute__(x)=', '-D__extension__=', '-D__asm__(x)='] for include_path in bsp.include_path: args.append('-I') args.append(include_path) for name, module in Modules.items(): for include_path in module.include_path: args.append('-I') args.append(include_path) source = "typedef int __builtin_va_list;\n" + source result = run(args, stdout=PIPE, stderr=PIPE, input=source.encode()) return result.stdout.decode()
[docs]class MicroblazeProgram(PynqMicroblaze): def __init__(self, mb_info, program_text, bsp=None): if hasattr(mb_info, 'mb_info'): mb_info = mb_info.mb_info if bsp is None: bsp = _find_bsp(mb_info['name']) ip_dict = PL.ip_dict ip_name = mb_info['ip_name'] if ip_name not in ip_dict.keys(): raise ValueError("No such IP {}.".format(ip_name)) ip_state = ip_dict[ip_name]['state'] force = False if ip_state and ip_state.startswith('/tmp/'): force = True modules = dependencies(program_text, bsp) lib_args = [] with tempfile.TemporaryDirectory() as tempdir: files = [path.join(tempdir, 'main.c')] args = ['mb-g++', '-o', path.join(tempdir, 'a.out'), '-Wno-multichar', '-fno-exceptions', '-ffunction-sections', '-Wl,-gc-sections'] args.extend(bsp.cflags) args.extend(bsp.sources) for include_path in bsp.include_path: args.append('-I{}'.format(include_path)) for lib_path in bsp.library_path: lib_args.append('-L{}'.format(lib_path)) for lib in bsp.libraries: lib_args.append('-l{}'.format(lib)) args.append('-Wl,{}'.format(bsp.linker_script)) args.extend(bsp.ldflags) for module in modules: files.extend(module.sources) for include_path in module.include_path: args.append('-I{}'.format(include_path)) for lib_path in module.library_path: lib_args.append('-L{}'.format(lib_path)) for lib in module.libraries: lib_args.append('-l{}'.format(lib)) with open(path.join(tempdir, 'main.c'), 'w') as f: f.write('#line 1 "cell_magic"\n') f.write(program_text) shutil.copy(path.join(tempdir, 'main.c'), '/tmp/last.c') result = run(args + files + lib_args, stdout=PIPE, stderr=PIPE) if result.returncode: raise RuntimeError(result.stderr.decode()) _ = run(['size', path.join(tempdir, 'a.out')], stdout=PIPE, stderr=PIPE) result = Popen(['nm', '-CSr', '--size-sort', path.join(tempdir, 'a.out')], stdout=PIPE, stderr=PIPE) _ = Popen(['head', '-10'], stdin=result.stdout, stdout=PIPE, stderr=None) shutil.copy(path.join(tempdir, 'a.out'), '/tmp/last.elf') result = run(['mb-objcopy', '-O', 'binary', path.join(tempdir, 'a.out'), path.join(tempdir, 'a.bin')], stderr=PIPE) if result.returncode: raise RuntimeError( "Objcopy Failed: {}".format(result.stderr.decode())) super().__init__(mb_info, path.join(tempdir, 'a.bin'), force) self.stream = InterruptMBStream(self) self.read = self.stream.read self.write = self.stream.write self.read_async = self.stream.read_async