diff --git a/programming_examples/basic/README.md b/programming_examples/basic/README.md index 1f9a8a9477..9d9a57169f 100644 --- a/programming_examples/basic/README.md +++ b/programming_examples/basic/README.md @@ -20,5 +20,4 @@ These programming examples provide a good starting point to illustrate how to bu * [Vector Reduce Max](./vector_reduce_max) - Single tile performs a reduction of a vector to return the `max` of the elements. * [Vector Reduce Min](./vector_reduce_min) - Single tile performs a reduction of a vector to return the `min` of the elements. * [Vector Exp](./vector_exp) - A simple element wise exponent function, using the look up table capabilities of the AI Engine. -* [Matrix Multiplication](./matrix_multiplication) - This directory contains multiple designs spanning: single core and multi-core (whole array) matrix-matrix multiplication, and matrix-vector multiplication designs. It also contains sweep infrastructure for benchmarking. -* [Hello World (printf log)](./log_hello_world) - Single tile performs a self-query and `printf` function where printed data is moved from local buffers to external memory to be read by the host processor. +* [Matrix Multiplication](./matrix_multiplication) - This directory contains multiple designs spanning: single core and multi-core (whole array) matrix-matrix multiplication, and matrix-vector multiplication designs. It also contains sweep infrastructure for benchmarking. \ No newline at end of file diff --git a/programming_examples/basic/log_hello_world/CMakeLists.txt b/programming_examples/basic/log_hello_world/CMakeLists.txt deleted file mode 100755 index c4ca0825d4..0000000000 --- a/programming_examples/basic/log_hello_world/CMakeLists.txt +++ /dev/null @@ -1,75 +0,0 @@ -# This file is licensed under the Apache License v2.0 with LLVM Exceptions. -# See https://llvm.org/LICENSE.txt for license information. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# -# (c) Copyright 2023 Advanced Micro Devices, Inc. - -# parameters -# -DBOOST_ROOT: Path to Boost install -# -DXRT_INC_DIR: Full path to src/runtime_src/core/include in XRT cloned repo -# -DXRT_LIB_DIR: Path to xrt_coreutil.lib -# -DTARGET_NAME: Target name to be built - -# cmake needs this line -cmake_minimum_required(VERSION 3.1) - -set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_REQUIRED YES) - -find_program(WSL NAMES powershell.exe) - -if (NOT WSL) - set(CMAKE_C_COMPILER gcc-13) - set(CMAKE_CXX_COMPILER g++-13) - set(BOOST_ROOT /usr/include/boost CACHE STRING "Path to Boost install") - set(XRT_INC_DIR /opt/xilinx/xrt/include CACHE STRING "Path to XRT cloned repo") - set(XRT_LIB_DIR /opt/xilinx/xrt/lib CACHE STRING "Path to xrt_coreutil.lib") -else() - set(BOOST_ROOT C:/Technical/thirdParty/boost_1_83_0 CACHE STRING "Path to Boost install") - set(XRT_INC_DIR C:/Technical/XRT/src/runtime_src/core/include CACHE STRING "Path to XRT cloned repo") - set(XRT_LIB_DIR C:/Technical/xrtIPUfromDLL CACHE STRING "Path to xrt_coreutil.lib") -endif() - -set(TARGET_NAME test CACHE STRING "Target to be built") - -SET (ProjectName ${TARGET_NAME}) -SET (currentTarget ${TARGET_NAME}) - -if ( WSL ) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) -endif () - -project(${ProjectName}) - -# Find packages -find_package(Boost REQUIRED) - -add_executable(${currentTarget} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../runtime_lib/test_lib/test_utils.cpp - test.cpp -) - -target_compile_definitions(${currentTarget} PUBLIC DISABLE_ABI_CHECK=1) - -target_include_directories (${currentTarget} PUBLIC - ${XRT_INC_DIR} - ${Boost_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR}/../../../runtime_lib/test_lib -) - -target_link_directories(${currentTarget} PUBLIC - ${XRT_LIB_DIR} - ${Boost_LIBRARY_DIRS} -) - -if (NOT WSL) - target_link_libraries(${currentTarget} PUBLIC - xrt_coreutil - boost_program_options - boost_filesystem - ) -else() - target_link_libraries(${currentTarget} PUBLIC - xrt_coreutil - ) -endif() diff --git a/programming_examples/basic/log_hello_world/Makefile b/programming_examples/basic/log_hello_world/Makefile deleted file mode 100755 index c5bcd8d5c3..0000000000 --- a/programming_examples/basic/log_hello_world/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -##===- Makefile -----------------------------------------------------------===## -# -# This file licensed under the Apache License v2.0 with LLVM Exceptions. -# See https://llvm.org/LICENSE.txt for license information. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# -##===----------------------------------------------------------------------===## - -include ../../makefile-common - -all: hello_world_elfstrings.csv - -targetname = helloWorld - -build/%.o: %.cc - mkdir -p ${@D} - cd ${@D} && xchesscc_wrapper ${CHESSCCWRAP2_FLAGS} -c $(<:%=../%) -o ${@F} - -build/hello_world.mlir: hello_world.py - mkdir -p ${@D} - python3 $< > $@ - -build/hello_world.xclbin: build/hello_world.mlir build/kernel.o - mkdir -p ${@D} - cd ${@D} && aiecc.py --aie-generate-cdo --aie-generate-ipu --no-compile-host \ - --xclbin-name=${@F} --ipu-insts-name=insts.txt $(<:%=../%) - -hello_world_elfstrings.csv: build/hello_world.xclbin - python3 elfStringParser.py --input ./build --output $@ - -${targetname}.exe: test.cpp - mkdir -p ${@D} - rm -rf _build - mkdir -p _build - cd _build && ${powershell} cmake .. -DTARGET_NAME=${targetname} - cd _build && ${powershell} cmake --build . --config Release -ifeq "${powershell}" "powershell.exe" - cp _build/${targetname}.exe $@ -else - cp _build/${targetname} $@ -endif - -run: ${targetname}.exe hello_world_elfstrings.csv - ${powershell} ./$< -x build/hello_world.xclbin -i build/insts.txt \ - -k MLIR_AIE -e $(word 2,$^) - -clean: - rm -rf build _build *.csv ${powershell}.exe diff --git a/programming_examples/basic/log_hello_world/README.md b/programming_examples/basic/log_hello_world/README.md deleted file mode 100644 index cee1dafe81..0000000000 --- a/programming_examples/basic/log_hello_world/README.md +++ /dev/null @@ -1,46 +0,0 @@ -## Simple Log Hello World - -This reference design demonstrates a simple, low overhead, printf-style log message from AIE tiles. - -Features: -* Low instruction memory overhead (based on variadic templates) -* Efficient transfers. - + Format string addresses are parsed from the compiled elfs host side. - + Data transfers from the AIE tile are just string addresses and parameters; no strings are sent. - + Host-side string addresses are used to look up format strings and populated with parameters. - -### Building and executing (on a phx laptop) -Type the following to build and run the design in a wsl terminal. -``` -make run -``` - -### Logging from the kernel code -Below is a simple example of how to use `npulog.h` in a kernel. -```c++ -#include "npulog.h" - -void kernel(uint32_t *logbuffer) { - NPULogger log(logbuffer, 2048); // buffer to use, and length of buffer - log.write("Hello!"); -} -``` - -### Extracting format string addresses at compile time -After building the `.xclbin` in the directory where the AIE Tile elfs are, call the following to create the mappings from the format strings to addresses. -```bash -python3 elfStringParser.py --input --output formatStrings.csv -``` - -### Decoding the log at runtime -At runtime we can run the NPU and then run a decoder on the output buffer to render all the strings. - -```c++ - #include "decodelog.hpp" - // ... - NPULogDecoder log_decoder("formatString.csv"); - for (const std::string &str : log_decoder.decode(logbuffer)) { - std::cout << str << std::endl; - } -``` - diff --git a/programming_examples/basic/log_hello_world/decodelog.hpp b/programming_examples/basic/log_hello_world/decodelog.hpp deleted file mode 100755 index dc73ad2d48..0000000000 --- a/programming_examples/basic/log_hello_world/decodelog.hpp +++ /dev/null @@ -1,138 +0,0 @@ -//===- decodelog.hpp ---------------------------------------000---*- C++ -//-*-===// -// -// This file is licensed under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// Copyright (C) 2023, Advanced Micro Devices, Inc. -// -//===----------------------------------------------------------------------===// - -#include "xrt/xrt_bo.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class NPULogDecoder { - // Parses the strings file to provide a decoder for parameterising the - // string messages from the AIE tiles - -private: - std::string _elfstrings_file; - std::map _str_map; - - void parse_str_map() { - std::ifstream file(_elfstrings_file); - if (!file.is_open()) { - std::cerr << "Error! unable to open the elfstrings file (" - << _elfstrings_file << ")\n"; - } - std::string line; - while (std::getline(file, line)) { - boost::char_separator sep(","); - boost::tokenizer> tokens(line, sep); - - auto it = tokens.begin(); - if (it == tokens.end()) { - // case where there are no tokens on the line - continue; - } - int address; - if (!(std::istringstream(*it) >> address)) { - // Handle the case where the first token cannot be converted to an int - continue; - } - ++it; - if (it == tokens.end()) { - // Handle the case where there's no second token - continue; - } - std::string format_str = *it; - _str_map[address] = format_str; - } - } - -public: - NPULogDecoder(std::string elfstrings_file) - : _elfstrings_file(elfstrings_file) { - parse_str_map(); - } - - // When given a string address return true if we have - // the format string for it - bool format_str_exists(uint32_t addr) { - return _str_map.find(addr) != _str_map.end(); - } - - // Peel off a message payload from the start of the buffer - // and render a format string with the parameters - uint32_t *renderNextStr(std::vector &log, uint32_t *buffer) { - uint32_t straddr = *buffer; - buffer++; - if (format_str_exists(straddr)) { - // Construct the string - std::string frmt = _str_map[straddr]; - - std::string out; - for (std::string::size_type i = 0; i < frmt.size(); ++i) { - if (frmt[i] == '%') { - // We need to replace this and the next - // char with an appropriately converted parameter - i++; - switch (frmt[i]) { - case 'd': { // int type - int intparam = *((int *)(buffer)); - out += std::to_string(intparam); - buffer++; - break; - } - case 'f': { // float type - float floatparam = *((float *)(buffer)); - out += std::to_string(floatparam); - buffer++; - break; - } - case 'u': { // unsigned type - unsigned unsignedparam = *((unsigned *)(buffer)); - out += std::to_string(unsignedparam); - buffer++; - break; - } - case 'x': { // hexadecimal type - unsigned hexparam = *((unsigned *)(buffer)); - std::stringstream stream; - stream << std::hex << hexparam; - out += stream.str(); - buffer++; - break; - } - } - } else { - out += frmt[i]; - } - } - - log.emplace_back(out); - } - return buffer; - } - - std::vector decode(xrt::bo buffer) { - uint32_t buffer_size = buffer.size(); - uint32_t *buffer_ptr = buffer.map(); - uint32_t *end_of_buffer = buffer_ptr + (buffer_size / sizeof(uint32_t)); - - std::vector rendered_log; - while (buffer_ptr < end_of_buffer) { - buffer_ptr = renderNextStr(rendered_log, buffer_ptr); - } - return rendered_log; - } -}; diff --git a/programming_examples/basic/log_hello_world/elfStringParser.py b/programming_examples/basic/log_hello_world/elfStringParser.py deleted file mode 100755 index c50415cc1e..0000000000 --- a/programming_examples/basic/log_hello_world/elfStringParser.py +++ /dev/null @@ -1,88 +0,0 @@ -# -# This file is licensed under the Apache License v2.0 with LLVM Exceptions. -# See https://llvm.org/LICENSE.txt for license information. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# -# (c) Copyright 2023 AMD Inc. - -import argparse -import os -import re -import subprocess -from typing import Dict - - -def call_unix_proc(cmd: str) -> str: - cmdlist = cmd.split(" ") - try: - output = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT) - return output.decode() - except subprocess.CalledProcessError as e: - print(f"ERROR! {cmd} failed \n\n{e.output.decode()}") - raise e - - -def _get_ro_offset(ofile: str) -> int: - s = f"readelf -S {ofile}" - out = call_unix_proc(s) - pattern = r"\s*\[\s*[0-9]+\]\s*\.rodata\.DMb\.1\s*PROGBITS\s*([0-9a-z]+)" - match = re.search(pattern, out) - if match: - return int(match.group(1), 16) - return int("70A00", 16) - - -def _gen_string_dict(stringsoutput: str, rooffset: int = 0) -> Dict[int, str]: - lines = stringsoutput.split("\n") - result = {} - first = True - first_val = 0 - for line in lines: - l = line.lstrip() - try: - hex_num, text = l.split(" ", 1) - if first: - first_val = int(hex_num, 16) - result[rooffset] = text - first = False - else: - result[(int(hex_num, 16) - first_val) + rooffset] = text - except: - pass - return result - - -def main(): - parser = argparse.ArgumentParser( - description="A utility to extract a json file of all the format strings and corresponding addresses/locations in an AIE design" - ) - parser.add_argument( - "--input", - required=True, - help="Path to the directory where the project was constructed", - ) - parser.add_argument("--output", default="elfstrings.csv") - args = parser.parse_args() - - # Collect all the elfs - ofiles = [] - for filename in os.listdir(args.input): - if filename.endswith(".elf"): - filepath = os.path.join(args.input, filename) - ofiles.append(filepath) - print(ofiles) - - res = {} - for ofile in ofiles: - strings_cmd = f"strings --radix x -a {ofile}" - object_strings_str = call_unix_proc(strings_cmd) - ro_offset = _get_ro_offset(ofile) - d = _gen_string_dict(object_strings_str, ro_offset) - res = {**res, **d} - with open(args.output, "w") as fp: - for addr, s in res.items(): - fp.write(f"{addr},{s}\n") - - -if __name__ == "__main__": - main() diff --git a/programming_examples/basic/log_hello_world/hello_world.py b/programming_examples/basic/log_hello_world/hello_world.py deleted file mode 100644 index b017d110b7..0000000000 --- a/programming_examples/basic/log_hello_world/hello_world.py +++ /dev/null @@ -1,64 +0,0 @@ -# This file is licensed under the Apache License v2.0 with LLVM Exceptions. -# See https://llvm.org/LICENSE.txt for license information. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# -# (c) Copyright 2023 AMD Inc. - -from aie.dialects.aie import * -from aie.dialects.aiex import * -from aie.dialects.scf import * -from aie.extras.context import mlir_mod_ctx - - -def printf(): - N = 512 - - with mlir_mod_ctx() as ctx: - - @device(AIEDevice.ipu) - def device_body(): - memRef_ty = T.memref(N, T.i32()) - - # AIE Core Function declarations - kernel = external_func("kernel", inputs=[memRef_ty, memRef_ty, memRef_ty]) - - # Tile declarations - ShimTile = tile(0, 0) - ComputeTile2 = tile(0, 2) - - # AIE-array data movement with object fifos - inOF = object_fifo("inOF", ShimTile, ComputeTile2, 2, memRef_ty) - outOF = object_fifo("outOF", ComputeTile2, ShimTile, 2, memRef_ty) - logoutOF = object_fifo("logoutOF", ComputeTile2, ShimTile, 2, memRef_ty) - - # Set up compute tiles - - # Compute tile 2 - @core(ComputeTile2, "kernel.o") - def core_body(): - elemOut = outOF.acquire(ObjectFifoPort.Produce, 1) - elemIn = inOF.acquire(ObjectFifoPort.Consume, 1) - elemLogout = logoutOF.acquire(ObjectFifoPort.Produce, 1) - call(kernel, [elemIn, elemOut, elemLogout]) - inOF.release(ObjectFifoPort.Consume, 1) - outOF.release(ObjectFifoPort.Produce, 1) - logoutOF.release(ObjectFifoPort.Produce, 1) - - # To/from AIE-array data movement - @FuncOp.from_py_func(memRef_ty, memRef_ty, memRef_ty) - def sequence(in_mem, out_mem, logout): - ipu_dma_memcpy_nd( - metadata="outOF", bd_id=0, mem=out_mem, sizes=[1, 1, 1, N] - ) - ipu_dma_memcpy_nd( - metadata="inOF", bd_id=1, mem=in_mem, sizes=[1, 1, 1, N] - ) - ipu_dma_memcpy_nd( - metadata="logoutOF", bd_id=2, mem=logout, sizes=[1, 1, 1, N] - ) - ipu_sync(column=0, row=0, direction=0, channel=0) - - print(ctx.module) - - -printf() diff --git a/programming_examples/basic/log_hello_world/kernel.cc b/programming_examples/basic/log_hello_world/kernel.cc deleted file mode 100755 index f0dc962ba9..0000000000 --- a/programming_examples/basic/log_hello_world/kernel.cc +++ /dev/null @@ -1,41 +0,0 @@ -//===- kernel.cc -------------------------------------------000---*- C++ -//-*-===// -// -// This file is licensed under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// Copyright (C) 2023, Advanced Micro Devices, Inc. -// -//===----------------------------------------------------------------------===// -#define NOCPP - -#include -#include -#include - -#include - -#include "npulog.h" - -extern "C" { - -void kernel(uint32_t *in_buffer, uint32_t *out_buffer, uint8_t *logbuffer) { - - NPULogger log(logbuffer, 2048); - log.write("Starting kernel execution!\n"); - - uint32_t col = (get_coreid() >> 16) & 0x0000FFFF; - uint32_t row = get_coreid() & 0x0000FFFF; - - aie::tile tile = aie::tile::current(); - uint64_t Tstart = tile.cycles(); - log.write("Core Location col=%u row=%u\n", col, row); - - memcpy(out_buffer, in_buffer, 2048); - - uint64_t Tend = tile.cycles(); - uint64_t cycles = Tend - Tstart; - log.write("Completed executing. cycles=%u\n", cycles); -} -} diff --git a/programming_examples/basic/log_hello_world/npulog.h b/programming_examples/basic/log_hello_world/npulog.h deleted file mode 100755 index 1dab3c56eb..0000000000 --- a/programming_examples/basic/log_hello_world/npulog.h +++ /dev/null @@ -1,84 +0,0 @@ -//===- npulog.h --------------------------------------------000---*- C++ -//-*-===// -// -// This file is licensed under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// Copyright (C) 2023, Advanced Micro Devices, Inc. -// -//===----------------------------------------------------------------------===// - -#include -#include - -class NPULogger { -private: - uint8_t *_buffer; - uint32_t _maxlen; - uint32_t _count; - uint32_t _dropped_msgs; - -public: - NPULogger(uint8_t *buffer, uint32_t len) : _buffer(buffer), _maxlen(len) { - _count = 0; - _dropped_msgs = 0; - } - - ~NPULogger() {} - - //---------------------------------- - // peel parameters of write - //---------------------------------- - // zeroth case - template - void log_peel_params(uint32_t *hmsg, uint32_t *cnt) { - { return; } - } - - // general case: peels the parameters off the argument list and appends them - // to the message - template - void log_peel_params(uint32_t *hmsg, uint32_t *cnt, const P1 &p1, - Param &...param) { - hmsg[*cnt + 1] = *( - (uint32_t *)&p1); // prune type and place raw bytes in the host message - *cnt = *cnt + 1; - log_peel_params(hmsg, cnt, param...); // keep on peeling - return; - } - //---------------------------------- - - template - void write(const char *msg, const Param &...param) { - if (almost_full(16)) { - _write("Log buffer is full -- we have dropped %u messages", - _dropped_msgs++); - _buffer -= 8; - _count -= 8; - return; - } - _write(msg, param...); - } - - template - void _write(const char *msg, const Param &...param) { - // create a message - uint32_t hmsg[40]; - - // assign the constant string addr in memory - hmsg[0] = (uint32_t)((uint32_t *)((void *)(msg))); - - // recursively peel off the parameters and assign - uint32_t param_cnt = 0; - log_peel_params(&hmsg[0], ¶m_cnt, param...); - - memcpy(_buffer, &hmsg, (param_cnt + 1) * 4); - _buffer += (param_cnt + 1) * 4; - _count += (param_cnt + 1) * 4; - - return; - } - - bool almost_full(uint32_t amount) { return _count >= (_maxlen - amount); } -}; diff --git a/programming_examples/basic/log_hello_world/run.lit b/programming_examples/basic/log_hello_world/run.lit deleted file mode 100644 index 096df253c7..0000000000 --- a/programming_examples/basic/log_hello_world/run.lit +++ /dev/null @@ -1,14 +0,0 @@ -// (c) Copyright 2023 Advanced Micro Devices, Inc. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// REQUIRES: ryzen_ai, chess -// -// RUN: xchesscc_wrapper aie2 -I %aietools/include -c %S/kernel.cc -o ./kernel.o -// RUN: %python %S/hello_world.py > ./aie.mlir -// RUN: %python aiecc.py --xbridge --aie-generate-cdo --aie-generate-ipu --no-compile-host --xclbin-name=aie.xclbin --ipu-insts-name=insts.txt ./aie.mlir -// RUN: clang %S/test.cpp -o test.exe -std=c++11 -Wall %xrt_flags -lrt -lstdc++ -lboost_program_options -lboost_filesystem -// RUN: %python %S/elfStringParser.py --input . --output elf_string.csv -// RUN: %run_on_ipu ./test.exe -x aie.xclbin -k MLIR_AIE -i insts.txt -e elf_string.csv | FileCheck %s -// CHECK: Starting kernel execution -// CHECK: Core Location col=1 row=2 -// CHECK: Completed executing. cycles= diff --git a/programming_examples/basic/log_hello_world/test.cpp b/programming_examples/basic/log_hello_world/test.cpp deleted file mode 100755 index face8d0757..0000000000 --- a/programming_examples/basic/log_hello_world/test.cpp +++ /dev/null @@ -1,191 +0,0 @@ -//===- test.cpp -------------------------------------------000---*- C++ -*-===// -// -// This file is licensed under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// Copyright (C) 2023, Advanced Micro Devices, Inc. -// -//===----------------------------------------------------------------------===// - -#include -#include -#include -#include -#include -#include -#include - -#include "decodelog.hpp" - -#include "xrt/xrt_bo.h" -#include "xrt/xrt_device.h" -#include "xrt/xrt_kernel.h" - -namespace po = boost::program_options; - -void check_arg_file_exists(po::variables_map &vm_in, std::string name) { - if (!vm_in.count(name)) { - throw std::runtime_error("Error: no " + name + " file was provided\n"); - } else { - std::ifstream test(vm_in[name].as()); - if (!test) { - throw std::runtime_error("The " + name + " file " + - vm_in[name].as() + - " does not exist.\n"); - } - } -} - -std::vector load_instr_sequence(std::string instr_path) { - std::ifstream instr_file(instr_path); - std::string line; - std::vector instr_v; - while (std::getline(instr_file, line)) { - std::istringstream iss(line); - uint32_t a; - if (!(iss >> std::hex >> a)) { - throw std::runtime_error("Unable to parse instruction file\n"); - } - instr_v.push_back(a); - } - return instr_v; -} - -namespace po = boost::program_options; - -int main(int argc, const char *argv[]) { - - // Program arguments parsing - po::options_description desc("Allowed options"); - desc.add_options()("help,h", "produce help message")( - "xclbin,x", po::value()->required(), - "the input xclbin path")( - "kernel,k", po::value()->required(), - "the kernel name in the XCLBIN (for instance PP_PRE_FD)")( - "verbosity,v", po::value()->default_value(0), - "the verbosity of the output")( - "elfstrings,e", po::value()->required(), - "CSV file of format strings and addresses")( - "instr,i", po::value()->required(), - "path of file containing userspace instructions to be sent to the LX6"); - po::variables_map vm; - - try { - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - if (vm.count("help")) { - std::cout << desc << "\n"; - return 1; - } - } catch (const std::exception &ex) { - std::cerr << ex.what() << "\n\n"; - std::cerr << "Usage:\n" << desc << "\n"; - return 1; - } - - check_arg_file_exists(vm, "xclbin"); - check_arg_file_exists(vm, "instr"); - check_arg_file_exists(vm, "elfstrings"); - - // Load instruction sequence - std::vector instr_v = - load_instr_sequence(vm["instr"].as()); - - int verbosity = vm["verbosity"].as(); - if (verbosity >= 1) - std::cout << "Sequence instr count: " << instr_v.size() << "\n"; - - // Start the XRT test code - // Get a device handle - unsigned int device_index = 0; - auto device = xrt::device(device_index); - - // Load the xclbin - if (verbosity >= 1) - std::cout << "Loading xclbin: " << vm["xclbin"].as() << "\n"; - auto xclbin = xrt::xclbin(vm["xclbin"].as()); - - if (verbosity >= 1) - std::cout << "Kernel opcode: " << vm["kernel"].as() << "\n"; - std::string Node = vm["kernel"].as(); - - // Get the kernel from the xclbin - auto xkernels = xclbin.get_kernels(); - auto xkernel = *std::find_if(xkernels.begin(), xkernels.end(), - [Node](xrt::xclbin::kernel &k) { - auto name = k.get_name(); - return name.rfind(Node, 0) == 0; - }); - auto kernelName = xkernel.get_name(); - - if (verbosity >= 1) - std::cout << "Registering xclbin: " << vm["xclbin"].as() - << "\n"; - - device.register_xclbin(xclbin); - - // get a hardware context - if (verbosity >= 1) - std::cout << "Getting hardware context.\n"; - xrt::hw_context context(device, xclbin.get_uuid()); - - // get a kernel handle - if (verbosity >= 1) - std::cout << "Getting handle to kernel:" << kernelName << "\n"; - auto kernel = xrt::kernel(context, kernelName); - - // set up the buffer objects - auto bo_instr = xrt::bo(device, instr_v.size() * sizeof(int), - XCL_BO_FLAGS_CACHEABLE, kernel.group_id(0)); - auto bo_in = - xrt::bo(device, 2048, XRT_BO_FLAGS_HOST_ONLY, kernel.group_id(2)); - auto bo_out = - xrt::bo(device, 2048, XRT_BO_FLAGS_HOST_ONLY, kernel.group_id(3)); - auto bo_logout = - xrt::bo(device, 2048, XRT_BO_FLAGS_HOST_ONLY, kernel.group_id(4)); - - if (verbosity >= 1) - std::cout << "Writing data into buffer objects.\n"; - - uint32_t *bufIn = bo_in.map(); - std::vector srcVecA; - for (int i = 0; i < 256; i++) { - srcVecA.push_back(42); - } - memcpy(bufIn, srcVecA.data(), (srcVecA.size() * sizeof(uint32_t))); - - // Copy instruction stream to xrt buffer object - void *bufInstr = bo_instr.map(); - memcpy(bufInstr, instr_v.data(), instr_v.size() * sizeof(int)); - - // sync host to device memories - bo_instr.sync(XCL_BO_SYNC_BO_TO_DEVICE); - bo_in.sync(XCL_BO_SYNC_BO_TO_DEVICE); - - // Execute the kernel and wait to finish - if (verbosity >= 1) - std::cout << "Running Kernel.\n"; - auto run = kernel(bo_instr, instr_v.size(), bo_in, bo_logout, bo_out); - run.wait(); - - if (verbosity >= 1) - std::cout << "Status after run: " << run.state() << "\n"; - - // Sync device to host memories - bo_out.sync(XCL_BO_SYNC_BO_FROM_DEVICE); - bo_logout.sync(XCL_BO_SYNC_BO_FROM_DEVICE); - - // Store result in cv::Mat - uint32_t *bufOut = bo_out.map(); - uint32_t *bufLogOut = bo_logout.map(); - - NPULogDecoder logdecode(vm["elfstrings"].as()); - std::vector logout = logdecode.decode(bo_out); - for (const std::string &str : logout) { - std::cout << str << std::endl; - } - - return 0; -}