Skip to content

Commit 670701e

Browse files
committed
Cross compiling for Xtensa
1 parent 99824b1 commit 670701e

File tree

9 files changed

+708
-1
lines changed

9 files changed

+708
-1
lines changed

CMakeLists.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ option(EXECUTORCH_BUILD_XNNPACK
112112
option(EXECUTORCH_BUILD_SDK
113113
"Build the ExecuTorch SDK library and the SDK example runner.")
114114

115+
option(EXECUTORCH_BUILD_XTENSA_EXAMPLE
116+
"Build the example targeted for the Xtensa Hifi4 DSP" OFF)
117+
115118
if(NOT BUCK2)
116119
set(BUCK2 buck2)
117120
endif()
@@ -235,9 +238,16 @@ add_subdirectory(schema)
235238
# full operators. Does not contain any backends.
236239
#
237240

241+
# Check if dl exists for this toolchain and only then link it.
242+
find_library(DL_LIBRARY_EXISTS NAMES dl)
243+
244+
# Check if the library was found
245+
if(DL_LIBRARY_EXISTS)
246+
target_link_libraries(executorch PRIVATE dl) # For dladdr()
247+
endif()
248+
238249
add_library(executorch ${_executorch__srcs})
239250
target_link_libraries(executorch PRIVATE program_schema)
240-
target_link_libraries(executorch PRIVATE dl) # For dladdr()
241251
target_include_directories(executorch PUBLIC ${_common_include_directories})
242252
target_compile_options(executorch PUBLIC ${_common_compile_options})
243253
if(MAX_KERNEL_NUM)
@@ -317,5 +327,9 @@ if(EXECUTORCH_BUILD_SDK)
317327
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/sdk)
318328
endif()
319329

330+
if(EXECUTORCH_BUILD_XTENSA_EXAMPLE)
331+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/examples/xtensa)
332+
endif()
333+
320334
# Print all summary
321335
executorch_print_configuration_summary()

examples/xtensa/CMakeLists.txt

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Set the minimum required version of CMake for this project.
2+
cmake_minimum_required(VERSION 3.10)
3+
4+
if(NOT CMAKE_CXX_STANDARD)
5+
set(CMAKE_CXX_STANDARD 17)
6+
endif()
7+
8+
# Set the project name.
9+
project(xtensa_executorch_example)
10+
11+
# Source root directory for executorch.
12+
if(NOT EXECUTORCH_ROOT)
13+
set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
14+
endif()
15+
16+
add_compile_options(
17+
-DSDK_DEBUGCONSOLE=1
18+
-DSERIAL_PORT_TYPE_UART=1
19+
-DDEBUG_CONSOLE_RX_ENABLE=0
20+
-DDEBUG
21+
-DCPU_MIMXRT685SFVKB_dsp
22+
-DMCUXPRESSO_SDK
23+
-g
24+
-O0
25+
-Wall
26+
-fsigned-char
27+
-Wno-missing-braces
28+
-fmessage-length=0
29+
-DPRINTF_FLOAT_ENABLE=1)
30+
31+
if(NOT DEFINED NXP_SDK_ROOT_DIR)
32+
message(FATAL_ERROR "NXP_SDK_ROOT_DIR is not set")
33+
endif()
34+
35+
set(SOURCES
36+
${NXP_SDK_ROOT_DIR}/components/lists/fsl_component_generic_list.c
37+
${NXP_SDK_ROOT_DIR}/components/uart/fsl_adapter_usart.c
38+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_clock.c
39+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_common.c
40+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_common_dsp.c
41+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_flexcomm.c
42+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_gpio.c
43+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_mu.c
44+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_reset.c
45+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers/fsl_usart.c
46+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/system_MIMXRT685S_dsp.c
47+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/utilities/debug_console_lite/fsl_assert.c
48+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/utilities/debug_console_lite/fsl_debug_console.c
49+
${NXP_SDK_ROOT_DIR}/boards/evkmimxrt685/dsp_examples/mu_polling/dsp/board_hifi4.c
50+
${NXP_SDK_ROOT_DIR}/boards/evkmimxrt685/dsp_examples/mu_polling/dsp/pin_mux.c
51+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/utilities/str/fsl_str.c
52+
)
53+
54+
add_library(dsp_mu_polling_libs STATIC ${SOURCES})
55+
56+
target_include_directories(dsp_mu_polling_libs PUBLIC
57+
${NXP_SDK_ROOT_DIR}
58+
${NXP_SDK_ROOT_DIR}/components/uart
59+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/drivers
60+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/utilities/debug_console_lite
61+
${NXP_SDK_ROOT_DIR}/components/lists
62+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S
63+
${NXP_SDK_ROOT_DIR}/CMSIS/Core/Include
64+
${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/utilities/str
65+
${NXP_SDK_ROOT_DIR}/boards/evkmimxrt685/dsp_examples/mu_polling/dsp
66+
)
67+
68+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ops)
69+
70+
# Generate the model header file
71+
add_custom_command(
72+
OUTPUT ${CMAKE_BINARY_DIR}/model_pte.h
73+
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/utils/gen_header.py
74+
--model_path ${MODEL_PATH} --header_output_path ${CMAKE_BINARY_DIR}
75+
COMMENT "Converting .pte model to header file..."
76+
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/utils/gen_header.py)
77+
78+
add_custom_target(gen_model_header DEPENDS ${CMAKE_BINARY_DIR}/model_pte.h)
79+
80+
add_executable(xtensa_executorch_example executor_runner.cpp)
81+
add_dependencies(xtensa_executorch_example gen_model_header)
82+
83+
target_include_directories(xtensa_executorch_example PUBLIC ${ROOT_DIR}/.. ${CMAKE_BINARY_DIR})
84+
85+
target_link_options(
86+
xtensa_executorch_example PRIVATE
87+
-mlsp=${NXP_SDK_ROOT_DIR}/devices/MIMXRT685S/xtensa/min-rt)
88+
target_link_libraries(xtensa_executorch_example dsp_mu_polling_libs
89+
xtensa_ops_lib executorch)
90+
91+
add_custom_command(
92+
TARGET xtensa_executorch_example
93+
POST_BUILD
94+
COMMAND
95+
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/utils/post_compilation.py
96+
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME} ${CMAKE_BINARY_DIR}
97+
COMMENT
98+
"Generating .bin files that can be used to flash the DSP with. Copy over
99+
the dsp_text_release.bin and dsp_data_release.bin that are generated into
100+
your NXP MCUXpresso IDE workspace and flash the DSP with these binaries."
101+
DEPENDS
102+
${CMAKE_CURRENT_LIST_DIR}/utils/post_compilation.py)

examples/xtensa/executor_runner.cpp

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
/**
10+
* @file
11+
*
12+
* This is a simple executor_runner that boots up the DSP, configures the serial
13+
* port, sends a bunch of test messages to the M33 core and then loads the model
14+
* defined in model_pte.h. It runs this model using the ops available in
15+
* xtensa/ops directory.
16+
*/
17+
18+
#include <fsl_debug_console.h>
19+
#include "fsl_device_registers.h"
20+
#include "fsl_mu.h"
21+
22+
#include "board_hifi4.h"
23+
#include "model_pte.h"
24+
#include "pin_mux.h"
25+
26+
#include <memory>
27+
#include <vector>
28+
29+
#include <executorch/extension/data_loader/buffer_data_loader.h>
30+
#include <executorch/runtime/executor/method.h>
31+
#include <executorch/runtime/executor/program.h>
32+
#include <executorch/runtime/platform/log.h>
33+
#include <executorch/runtime/platform/profiler.h>
34+
#include <executorch/runtime/platform/runtime.h>
35+
#include <executorch/util/util.h>
36+
37+
static uint8_t method_allocator_pool[18 * 1024U]; // 4 MB
38+
39+
using namespace torch::executor;
40+
#include <xtensa/config/core.h>
41+
42+
#define APP_MU MUB
43+
/* Flag indicates Core Boot Up*/
44+
#define BOOT_FLAG 0x01U
45+
/* Channel transmit and receive register */
46+
#define CHN_MU_REG_NUM 0U
47+
/* How many message is used to test message sending */
48+
#define MSG_LENGTH 32U
49+
50+
using torch::executor::Error;
51+
using torch::executor::Result;
52+
53+
void LED_INIT();
54+
void LED_TOGGLE();
55+
56+
void LED_INIT() {
57+
CLOCK_EnableClock(kCLOCK_HsGpio0);
58+
RESET_PeripheralReset(kHSGPIO0_RST_SHIFT_RSTn);
59+
gpio_pin_config_t pin_config = {kGPIO_DigitalOutput, LOGIC_LED_OFF};
60+
GPIO_PinInit(
61+
BOARD_LED_RED_GPIO,
62+
BOARD_LED_RED_GPIO_PORT,
63+
BOARD_LED_RED_GPIO_PIN,
64+
&pin_config);
65+
}
66+
67+
void LED_TOGGLE() {
68+
LED_RED_TOGGLE();
69+
}
70+
71+
/*!
72+
* @brief Function to create delay for Led blink.
73+
*/
74+
void delay(void) {
75+
volatile uint32_t i = 0;
76+
for (i = 0; i < 5000000; ++i) {
77+
__NOP();
78+
}
79+
}
80+
81+
void et_pal_emit_log_message(
82+
et_timestamp_t timestamp,
83+
et_pal_log_level_t level,
84+
const char* filename,
85+
__ET_UNUSED const char* function,
86+
size_t line,
87+
const char* message,
88+
__ET_UNUSED size_t length) {
89+
PRINTF("\r%s\n", message);
90+
}
91+
92+
int main(int argc, char** argv) {
93+
/* Init board hardware. */
94+
BOARD_InitBootPins();
95+
96+
/* Initialize LED */
97+
LED_INIT();
98+
99+
/* MUB init */
100+
MU_Init(APP_MU);
101+
102+
/* Send flag to Core 0 to indicate Core 1 has startup */
103+
MU_SetFlags(APP_MU, BOOT_FLAG);
104+
105+
BOARD_InitDebugConsole();
106+
ET_LOG(Info, "Booted up in DSP.");
107+
108+
torch::executor::runtime_init();
109+
110+
auto loader =
111+
torch::executor::util::BufferDataLoader(model_pte, sizeof(model_pte));
112+
113+
Result<torch::executor::Program> program =
114+
torch::executor::Program::load(&loader);
115+
if (!program.ok()) {
116+
ET_LOG(
117+
Error,
118+
"ET: Program loading failed @ 0x%p: 0x%" PRIx32,
119+
model_pte,
120+
program.error());
121+
}
122+
123+
ET_LOG(
124+
Info,
125+
"AET: Model buffer loaded, has %u methods",
126+
program->num_methods());
127+
128+
const char* method_name = nullptr;
129+
{
130+
const auto method_name_result = program->get_method_name(0);
131+
ET_CHECK_MSG(method_name_result.ok(), "Program has no methods");
132+
method_name = *method_name_result;
133+
}
134+
ET_LOG(Info, "ET: Running method %s", method_name);
135+
136+
Result<torch::executor::MethodMeta> method_meta =
137+
program->method_meta(method_name);
138+
if (!method_meta.ok()) {
139+
ET_LOG(
140+
Error,
141+
"ET: Failed to get method_meta for %s: 0x%x",
142+
method_name,
143+
(unsigned int)method_meta.error());
144+
}
145+
146+
torch::executor::MemoryAllocator method_allocator{
147+
torch::executor::MemoryAllocator(
148+
sizeof(method_allocator_pool), method_allocator_pool)};
149+
150+
std::vector<std::unique_ptr<uint8_t[]>> planned_buffers; // Owns the memory
151+
std::vector<torch::executor::Span<uint8_t>>
152+
planned_spans; // Passed to the allocator
153+
size_t num_memory_planned_buffers = method_meta->num_memory_planned_buffers();
154+
155+
for (size_t id = 0; id < num_memory_planned_buffers; ++id) {
156+
size_t buffer_size =
157+
static_cast<size_t>(method_meta->memory_planned_buffer_size(id).get());
158+
ET_LOG(
159+
Info,
160+
"ET: Setting up planned buffer %zu, size %zu.",
161+
id,
162+
buffer_size);
163+
164+
planned_buffers.push_back(std::make_unique<uint8_t[]>(buffer_size));
165+
planned_spans.push_back({planned_buffers.back().get(), buffer_size});
166+
}
167+
168+
torch::executor::HierarchicalAllocator planned_memory(
169+
{planned_spans.data(), planned_spans.size()});
170+
171+
torch::executor::MemoryManager memory_manager(
172+
&method_allocator, &planned_memory);
173+
174+
Result<torch::executor::Method> method =
175+
program->load_method(method_name, &memory_manager);
176+
if (!method.ok()) {
177+
ET_LOG(
178+
Error,
179+
"Loading of method %s failed with status 0x%" PRIx32,
180+
method_name,
181+
method.error());
182+
}
183+
184+
ET_LOG(Info, "Method loaded.");
185+
torch::executor::util::PrepareInputTensors(*method);
186+
ET_LOG(Info, "Starting the model execution...");
187+
188+
Error status = method->execute();
189+
ET_LOG(Info, "Executed model");
190+
if (status != Error::Ok) {
191+
ET_LOG(
192+
Error,
193+
"Execution of method %s failed with status 0x%" PRIx32,
194+
method_name,
195+
status);
196+
} else {
197+
ET_LOG(Info, "Model executed successfully.");
198+
}
199+
200+
while (1) {
201+
delay();
202+
LED_TOGGLE();
203+
}
204+
205+
return 0;
206+
}

0 commit comments

Comments
 (0)