Skip to content

Commit 0fdec56

Browse files
authored
Specialize xrt::aie::program as specific ELF type (#8810)
* Specialize xrt::aie::program as specific ELF type Add xrt::aie::program as a first class ELF type that is interchangeable with xrt::elf provided the ELF represents an AIE program. While xrt::elf is a basic wrapper for any ELF, the xrt::aie::program extends the APIs of xrt::elf for mining of data specific to AIE, such as kernel meta data and extraction of control code for patching by AIEBU. Signed-off-by: Soren Soe <[email protected]> * Fix bad forwarding overload Signed-off-by: Soren Soe <[email protected]> --------- Signed-off-by: Soren Soe <[email protected]>
1 parent 312ae79 commit 0fdec56

File tree

6 files changed

+256
-27
lines changed

6 files changed

+256
-27
lines changed

src/runtime_src/core/common/api/xrt_elf.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#define XCL_DRIVER_DLL_EXPORT // exporting xrt_elf.h
44
#define XRT_API_SOURCE // exporting xrt_elf.h
55
#define XRT_CORE_COMMON_SOURCE // in same dll as core_common
6+
#include "xrt/experimental/xrt_aie.h"
67
#include "xrt/experimental/xrt_elf.h"
78
#include "xrt/xrt_uuid.h"
89

@@ -144,3 +145,26 @@ get_cfg_uuid() const
144145
}
145146

146147
} // namespace xrt
148+
149+
////////////////////////////////////////////////////////////////
150+
// xrt::aie::program C++ API implementation (xrt_aie.h)
151+
////////////////////////////////////////////////////////////////
152+
namespace xrt::aie {
153+
154+
void
155+
program::
156+
valid_or_error()
157+
{
158+
// Validate that the ELF file is a valid AIE program
159+
}
160+
161+
program::size_type
162+
program::
163+
get_partition_size() const
164+
{
165+
return get_handle()->get_partition_size();
166+
}
167+
168+
} // namespace xrt::aie
169+
170+

src/runtime_src/core/common/api/xrt_module.cpp

+20-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "core/common/config_reader.h"
77
#include "core/common/message.h"
88
#include "xrt/experimental/xrt_module.h"
9+
#include "xrt/experimental/xrt_aie.h"
910
#include "xrt/experimental/xrt_elf.h"
1011
#include "xrt/experimental/xrt_ext.h"
1112

@@ -725,6 +726,7 @@ class module_elf : public module_impl
725726
// module class for ELFs with os_abi - Elf_Amd_Aie2p & ELF_Amd_Aie2p_config
726727
class module_elf_aie2p : public module_elf
727728
{
729+
xrt::aie::program m_program;
728730
// New Elf of Aie2p contain multiple ctrltext, ctrldata sections
729731
// sections will be of format .ctrltext.* where .* has index of that section type
730732
// Below maps has this index as key and value is pair of <section index, data buffer>
@@ -837,8 +839,8 @@ class module_elf_aie2p : public module_elf
837839
arg.dir = xrt_core::xclbin::kernel_argument::direction::input;
838840
// if arg has pointer(*) in its name (eg: char*, void*) it is of type global otherwise scalar
839841
arg.type = (str.find('*') != std::string::npos)
840-
? xrt_core::xclbin::kernel_argument::argtype::global
841-
: xrt_core::xclbin::kernel_argument::argtype::scalar;
842+
? xrt_core::xclbin::kernel_argument::argtype::global
843+
: xrt_core::xclbin::kernel_argument::argtype::scalar;
842844

843845
// At present only global args are supported
844846
// TODO : Add support for scalar args in ELF flow
@@ -1044,25 +1046,25 @@ class module_elf_aie2p : public module_elf
10441046
}
10451047

10461048
std::string argnm{ symname, symname + std::min(strlen(symname), dynstr->get_size()) };
1047-
patcher::patch_info pi = patch_scheme == patcher::symbol_type::scalar_32bit_kind ?
1048-
// st_size is is encoded using register value mask for scaler_32
1049-
// for other pacthing scheme it is encoded using size of dma
1050-
patcher::patch_info{ offset, add_end_addr, static_cast<uint32_t>(sym->st_size) } :
1051-
patcher::patch_info{ offset, add_end_addr, 0 };
1049+
patcher::patch_info pi = patch_scheme == patcher::symbol_type::scalar_32bit_kind
1050+
// st_size is is encoded using register value mask for scaler_32
1051+
// for other pacthing scheme it is encoded using size of dma
1052+
? patcher::patch_info{ offset, add_end_addr, static_cast<uint32_t>(sym->st_size) }
1053+
: patcher::patch_info{ offset, add_end_addr, 0 };
10521054

10531055
auto key_string = generate_key_string(argnm, buf_type, sec_index);
10541056

10551057
if (auto search = m_arg2patcher.find(key_string); search != m_arg2patcher.end())
10561058
search->second.m_ctrlcode_patchinfo.emplace_back(pi);
1057-
else {
1059+
else
10581060
m_arg2patcher.emplace(std::move(key_string), patcher{patch_scheme, {pi}, buf_type});
1059-
}
10601061
}
10611062
}
10621063

10631064
public:
10641065
explicit module_elf_aie2p(const xrt::elf& elf)
10651066
: module_elf{elf}
1067+
, m_program{elf}
10661068
{
10671069
initialize_kernel_info();
10681070
initialize_buf(patcher::buf_type::ctrltext, m_instr_buf_map);
@@ -1176,6 +1178,7 @@ class module_elf_aie2p : public module_elf
11761178
// module class for ELFs with os_abi - Elf_Amd_Aie2ps
11771179
class module_elf_aie2ps : public module_elf
11781180
{
1181+
xrt::aie::program m_program;
11791182
std::vector<ctrlcode> m_ctrlcodes;
11801183
buf m_dump_buf; // buffer to hold .dump section used for debug/trace
11811184

@@ -1405,7 +1408,8 @@ class module_elf_aie2ps : public module_elf
14051408

14061409
public:
14071410
explicit module_elf_aie2ps(const xrt::elf& elf)
1408-
: module_elf(elf)
1411+
: module_elf{elf}
1412+
, m_program{elf}
14091413
{
14101414
std::vector<size_t> pad_offsets;
14111415
initialize_column_ctrlcode(pad_offsets);
@@ -2311,8 +2315,8 @@ dump_dtrace_buffer(const xrt::module& module)
23112315

23122316
} // xrt_core::module_int
23132317

2314-
namespace
2315-
{
2318+
namespace {
2319+
23162320
static std::shared_ptr<xrt::module_elf>
23172321
construct_module_elf(const xrt::elf& elf)
23182322
{
@@ -2327,13 +2331,14 @@ construct_module_elf(const xrt::elf& elf)
23272331
throw std::runtime_error("unknown ELF type passed\n");
23282332
}
23292333
}
2330-
}
2334+
2335+
} // namespace
23312336

23322337
////////////////////////////////////////////////////////////////
23332338
// xrt_module C++ API implementation (xrt_module.h)
23342339
////////////////////////////////////////////////////////////////
2335-
namespace xrt
2336-
{
2340+
namespace xrt {
2341+
23372342
module::
23382343
module(const xrt::elf& elf)
23392344
: detail::pimpl<module_impl>(construct_module_elf(elf))
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,85 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright (C) 2021 Xilinx, Inc. All rights reserved.
3+
// Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
4+
#ifndef XRT_EXPERIMENTAL_AIE_H
5+
#define XRT_EXPERIMENTAL_AIE_H
6+
#include "xrt/xrt_aie.h"
7+
#include "xrt/experimental/xrt_elf.h"
8+
9+
#ifdef __cplusplus
10+
#include <type_traits>
11+
12+
namespace xrt::aie {
13+
114
/**
2-
* Copyright (C) 2021 Xilinx, Inc
3-
* ZNYQ XRT Library layered on top of ZYNQ zocl kernel driver
15+
* An aie::program object is a representaiton of a program to be executed
16+
* on the AIE. The program is an ELF file with sections and data
17+
* specific to the AIE.
418
*
5-
* Licensed under the Apache License, Version 2.0 (the "License"). You may
6-
* not use this file except in compliance with the License. A copy of the
7-
* License is located at
19+
* A program is added to a hardware context either when the hardware
20+
* context is contructed or by later adding the program to an existing
21+
* hardware context.
822
*
9-
* http://www.apache.org/licenses/LICENSE-2.0
23+
* An aie::program object can be created from an existing xrt::elf object
24+
* provided the ELF represents an AIE program. It can also be constructed
25+
* from a file or stream as provided by class xrt::elf.
1026
*
11-
* Unless required by applicable law or agreed to in writing, software
12-
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13-
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14-
* License for the specific language governing permissions and limitations
15-
* under the License.
27+
* The xrt::aie::program and xrt::elf are interchangable; the former
28+
* can be assigned to the latter, and the former can be constructed
29+
* from the latter without object slicing since the xrt::aie::program
30+
* is sharing same underlying implmenentation as xrt::elf.
1631
*/
17-
#include "xrt/xrt_aie.h"
32+
class program : public xrt::elf
33+
{
34+
// Validate that the ELF represents an AIE program
35+
XRT_API_EXPORT
36+
void
37+
valid_or_error();
38+
39+
public:
40+
using size_type = uint32_t;
41+
42+
/**
43+
* program() - Create a program object using xrt::elf constructors.
44+
*
45+
* Construction fails if the ELF is not a valid AIE program.
46+
*
47+
* This constructor is enabled only for types that do not match
48+
* program, this avoids forwaring reference overload
49+
*/
50+
template <typename ArgType,
51+
typename = std::enable_if_t<!std::is_same_v<std::decay_t<ArgType>, program>>>
52+
explicit
53+
program(ArgType&& arg)
54+
: xrt::elf{std::forward<ArgType>(arg)}
55+
{
56+
valid_or_error();
57+
}
58+
59+
/**
60+
* program() - Create a program object from an existing ELF.
61+
*
62+
* Construction fails if the ELF is not a valid AIE program.
63+
*/
64+
explicit
65+
program(xrt::elf xe)
66+
: xrt::elf{std::move(xe)}
67+
{
68+
valid_or_error();
69+
}
70+
71+
/**
72+
* get_partition_size() - Required partition size to run the program
73+
*
74+
* The partition size is used to configure a hardware context such
75+
* that it spans columns sufficient to run the program.
76+
*/
77+
XRT_API_EXPORT
78+
size_type
79+
get_partition_size() const;
80+
};
81+
82+
} // namespace xrt::aie
83+
84+
#endif // __cplusplus
85+
#endif // XRT_EXPERIMENTAL_AIE_H

src/runtime_src/core/include/xrt/experimental/xrt_elf.h

+6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ class elf : public detail::pimpl<elf_impl>
4848
explicit
4949
elf(std::istream& stream);
5050

51+
/**
52+
* get_cfg_uuid() - Get the configuration UUID of the elf
53+
*
54+
* @return
55+
* The configuration UUID of the elf
56+
*/
5157
XRT_API_EXPORT
5258
xrt::uuid
5359
get_cfg_uuid() const;

tests/xrt/elf/CMakeLists.txt

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
3+
CMAKE_MINIMUM_REQUIRED(VERSION 3.16.0)
4+
PROJECT(elf)
5+
6+
set(CMAKE_CXX_STANDARD 17)
7+
set(CMAKE_CXX_STANDARD_REQUIRED OFF)
8+
set(CMAKE_VERBOSE_MAKEFILE ON)
9+
10+
if (MSVC)
11+
add_compile_options(/Zc:__cplusplus)
12+
endif()
13+
14+
find_package(XRT REQUIRED HINTS ${XILINX_XRT}/share/cmake/XRT)
15+
message("-- XRT_INCLUDE_DIRS=${XRT_INCLUDE_DIRS}")
16+
17+
add_executable(elf main.cpp)
18+
target_include_directories(elf PRIVATE ${XRT_INCLUDE_DIRS})
19+
target_link_libraries(elf PRIVATE XRT::xrt_coreutil)
20+
21+
install(TARGETS elf)

tests/xrt/elf/main.cpp

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
3+
4+
#include "xrt/experimental/xrt_aie.h"
5+
#include "xrt/experimental/xrt_elf.h"
6+
7+
#include <iostream>
8+
#include <string>
9+
#include <vector>
10+
11+
static void
12+
usage()
13+
{
14+
std::cout << "usage: %s [options] -k <bitstream>\n\n";
15+
std::cout << " --elf <file>\n";
16+
std::cout << " [-h]\n\n";
17+
}
18+
19+
static void
20+
true_or_error(bool cond, const std::string& msg)
21+
{
22+
if (!cond)
23+
throw std::runtime_error("Error: condition failed - " + msg);
24+
}
25+
26+
static void
27+
test_elf(const std::string& elf_fnm)
28+
{
29+
xrt::elf elf(elf_fnm);
30+
}
31+
32+
static void
33+
test_program(const std::string& elf_fnm)
34+
{
35+
xrt::elf elf{elf_fnm};
36+
xrt::aie::program program1{elf_fnm};
37+
true_or_error(elf.get_handle() != program1.get_handle(), "expected different elf handles");
38+
39+
xrt::aie::program program2{elf};
40+
true_or_error(elf.get_handle() == program2.get_handle(), "expected same elf handles");
41+
42+
//auto col2 = program2.get_partition_size();
43+
44+
xrt::aie::program program3{program2};
45+
true_or_error(elf.get_handle() == program3.get_handle(), "expected same elf handles");
46+
47+
xrt::aie::program program4{std::move(program3)};
48+
true_or_error(elf.get_handle() == program4.get_handle(), "expected same elf handles");
49+
}
50+
51+
static void
52+
test_module(const std::string& elf_fnm)
53+
{
54+
}
55+
56+
static int
57+
run(int argc, char** argv)
58+
{
59+
if (argc < 2) {
60+
usage();
61+
return 1;
62+
}
63+
64+
std::string elf_fnm;
65+
66+
std::vector<std::string> args{argv + 1, argv + argc};
67+
std::string cur;
68+
for (const auto& arg : args) {
69+
if (arg == "-h") {
70+
usage();
71+
return 0;
72+
}
73+
74+
if (arg[0] == '-')
75+
cur = arg.substr(arg.find_first_not_of("-"));
76+
77+
else if (cur == "elf")
78+
elf_fnm = arg;
79+
}
80+
81+
if (elf_fnm.empty()) {
82+
std::cout << "Error: ELF file not specified\n";
83+
return 1;
84+
}
85+
86+
test_elf(elf_fnm);
87+
test_program(elf_fnm);
88+
test_module(elf_fnm);
89+
90+
return 0;
91+
}
92+
93+
int main(int argc, char* argv[])
94+
{
95+
try {
96+
return run(argc, argv);
97+
}
98+
catch (const std::exception& ex) {
99+
std::cout << "Caught exception: " << ex.what() << '\n';
100+
}
101+
catch (...) {
102+
std::cout << "Caught unknown exception\n";
103+
}
104+
return 1;
105+
}

0 commit comments

Comments
 (0)