Beispiel #1
0
def print_kernel_xml(name: str, ports: Iterable[tapa.instance.Port],
                     kernel_xml: IO[str]) -> None:
    """Generate kernel.xml file.

  Args:
    name: name of the kernel.
    ports: Iterable of tapa.instance.Port.
    kernel_xml: file object to write to.
  """
    args = []
    for port in ports:
        if port.cat == tapa.instance.Instance.Arg.Cat.SCALAR:
            cat = backend.Cat.SCALAR
        elif port.cat in {
                tapa.instance.Instance.Arg.Cat.MMAP,
                tapa.instance.Instance.Arg.Cat.ASYNC_MMAP
        }:
            cat = backend.Cat.MMAP
        elif port.cat == tapa.instance.Instance.Arg.Cat.ISTREAM:
            cat = backend.Cat.ISTREAM
        elif port.cat == tapa.instance.Instance.Arg.Cat.OSTREAM:
            cat = backend.Cat.OSTREAM
        else:
            raise ValueError(f'unexpected port.cat: {port.cat}')

        args.append(
            backend.Arg(
                cat=cat,
                name=port.name,
                port='',  # use defaults
                ctype=port.ctype,
                width=port.width,
            ))
    backend.print_kernel_xml(name, args, kernel_xml)
Beispiel #2
0
def print_kernel_xml(
    name: str,
    inputs: Iterable[Tuple[str, str, int, str]],
    outputs: Iterable[Tuple[str, str, int, str]],
    kernel_xml: TextIO,
    interface: str = 'm_axi',
) -> None:
    """Generate kernel.xml file.

  Args:
    name: Name of the kernel.
    inputs: Iterable of (port_name, bundle_name, width, _) of input ports.
    outputs: Iterable of (port_name, bundle_name, width, _) of output ports.
    kernel_xml: File object to write to.
    interface: Interface type, supported values are 'm_axi' and 'axis'.
  """
    args: List[backend.Arg] = []
    if interface == 'm_axi':
        for ports in outputs, inputs:
            for port_name, bundle_name, width, _ in ports:
                args.append(
                    backend.Arg(
                        cat=backend.Cat.MMAP,
                        name=port_name,
                        port=bundle_name,
                        ctype=f'ap_uint<{width}>*',
                        width=width,
                    ))
        args.append(
            backend.Arg(
                cat=backend.Cat.SCALAR,
                name='coalesced_data_num',
                port='',
                ctype='uint64_t',
                width=64,
            ))
    elif interface == 'axis':
        for cat, ports in ((backend.Cat.ISTREAM, inputs), (backend.Cat.OSTREAM,
                                                           outputs)):
            for port_name, _, width, _ in ports:
                ctype = f'stream<ap_axiu<{width}, 0, 0, 0>>&'
                args.append(
                    backend.Arg(
                        cat=cat,
                        name=port_name,
                        port='',
                        ctype=ctype,
                        width=width,
                    ))
    else:
        raise util.InternalError(f'unexpected interface `{interface}`')

    backend.print_kernel_xml(name=name, args=args, kernel_xml=kernel_xml)
Beispiel #3
0
def print_code(stencil, xo_file, platform=None, jobs=os.cpu_count()):
    """Generate hardware object file for the given Stencil.

  Working `vivado` and `vivado_hls` is required in the PATH.

  Args:
    stencil: Stencil object to generate from.
    xo_file: file object to write to.
    platform: path to the SDAccel platform directory.
    jobs: maximum number of jobs running in parallel.
  """

    m_axi_names = []
    m_axi_bundles = []
    inputs = []
    outputs = []
    for stmt in stencil.output_stmts + stencil.input_stmts:
        for bank in stmt.dram:
            haoda_type = 'uint%d' % stencil.burst_width
            bundle_name = util.get_bundle_name(stmt.name, bank)
            m_axi_names.append(bundle_name)
            m_axi_bundles.append((bundle_name, haoda_type))

    for stmt in stencil.output_stmts:
        for bank in stmt.dram:
            haoda_type = 'uint%d' % stencil.burst_width
            bundle_name = util.get_bundle_name(stmt.name, bank)
            outputs.append((util.get_port_name(stmt.name,
                                               bank), bundle_name, haoda_type,
                            util.get_port_buf_name(stmt.name, bank)))
    for stmt in stencil.input_stmts:
        for bank in stmt.dram:
            haoda_type = 'uint%d' % stencil.burst_width
            bundle_name = util.get_bundle_name(stmt.name, bank)
            inputs.append((util.get_port_name(stmt.name,
                                              bank), bundle_name, haoda_type,
                           util.get_port_buf_name(stmt.name, bank)))

    top_name = stencil.app_name + '_kernel'

    if 'XDEVICE' in os.environ:
        xdevice = os.environ['XDEVICE'].replace(':', '_').replace('.', '_')
        if platform is None or not os.path.exists(platform):
            platform = os.path.join('/opt/xilinx/platforms', xdevice)
        if platform is None or not os.path.exists(platform):
            if 'XILINX_SDX' in os.environ:
                platform = os.path.join(os.environ['XILINX_SDX'], 'platforms',
                                        xdevice)
    if platform is None or not os.path.exists(platform):
        raise ValueError('Cannot determine platform from environment.')
    device_info = backend.get_device_info(platform)

    with tempfile.TemporaryDirectory(prefix='sodac-xrtl-') as tmpdir:
        dataflow_kernel = os.path.join(tmpdir, 'dataflow_kernel.cpp')
        with open(dataflow_kernel, 'w') as dataflow_kernel_obj:
            print_dataflow_hls_interface(util.Printer(dataflow_kernel_obj),
                                         top_name, inputs, outputs)

        kernel_xml = os.path.join(tmpdir, 'kernel.xml')
        with open(kernel_xml, 'w') as kernel_xml_obj:
            backend.print_kernel_xml(top_name, outputs + inputs,
                                     kernel_xml_obj)

        kernel_file = os.path.join(tmpdir, 'kernel.cpp')
        with open(kernel_file, 'w') as kernel_fileobj:
            hls_kernel.print_code(stencil, kernel_fileobj)

        super_source = stencil.dataflow_super_source
        with concurrent.futures.ThreadPoolExecutor(
                max_workers=jobs) as executor:
            threads = []
            for module_id in range(len(super_source.module_traits)):
                threads.append(
                    executor.submit(synthesis_module, tmpdir, [kernel_file],
                                    util.get_func_name(module_id),
                                    device_info))
            threads.append(
                executor.submit(synthesis_module, tmpdir, [dataflow_kernel],
                                top_name, device_info))
            for future in concurrent.futures.as_completed(threads):
                returncode, stdout, stderr = future.result()
                log_func = _logger.error if returncode != 0 else _logger.debug
                if stdout:
                    log_func(stdout.decode())
                if stderr:
                    log_func(stderr.decode())
                if returncode != 0:
                    util.pause_for_debugging()
                    sys.exit(returncode)

        hdl_dir = os.path.join(tmpdir, 'hdl')
        with open(os.path.join(hdl_dir, 'Dataflow.v'), mode='w') as dataflow_v:
            print_top_module(backend.VerilogPrinter(dataflow_v),
                             stencil.dataflow_super_source, inputs, outputs)

        util.pause_for_debugging()

        xo_filename = os.path.join(tmpdir, stencil.app_name + '.xo')
        with backend.PackageXo(xo_filename, top_name, kernel_xml, hdl_dir,
                               m_axi_names, [dataflow_kernel]) as proc:
            stdout, stderr = proc.communicate()
        log_func = _logger.error if proc.returncode != 0 else _logger.debug
        log_func(stdout.decode())
        log_func(stderr.decode())
        with open(xo_filename, mode='rb') as xo_fileobj:
            shutil.copyfileobj(xo_fileobj, xo_file)