...
 
Commits (3)
    https://gitcode.net/xusiwei1236/tflite-micro/-/commit/33db40fb62194730a2a71db8f6e52a7f9d781a77 Flatten kernel namespace: RESHAPE (#2106) 2023-07-06T15:57:35+00:00 David Davis ddavis-2015@users.noreply.github.com @tensorflow/micro Flatten namespace for kernel operator RESHAPE Update unit tests namespace usage Update MicroOpResolver namespace usage bug=fixes #2105 https://gitcode.net/xusiwei1236/tflite-micro/-/commit/7837d79876e92919777f30024303677471be2acb Add test for MicroAllocator null pointer check (#2108) 2023-07-06T17:35:47+00:00 David Davis ddavis-2015@users.noreply.github.com @tensorflow/micro Add test for persistent tensor allocation failure by the MicroAllocator when arena memory is exhausted. This PR adds a test for previously merged PR #2038. bug=fixes #2107 https://gitcode.net/xusiwei1236/tflite-micro/-/commit/ef0a7b025a9d78dee0b81d7d27053f3aff097fb1 DebugLog changes (#2073) 2023-07-06T20:21:19+00:00 David Davis ddavis-2015@users.noreply.github.com @tensorflow/micro Change DebugLog to allow stdio style formatted output using either <cstdio> or a third party printf library. Remove micro_string code. bug=fixes #2083
/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -15,14 +15,13 @@ limitations under the License.
#ifndef TENSORFLOW_LITE_KERNELS_OP_MACROS_H_
#define TENSORFLOW_LITE_KERNELS_OP_MACROS_H_
#include "tensorflow/lite/micro/debug_log.h"
#if !defined(TF_LITE_MCU_DEBUG_LOG)
#include <cstdlib>
#define TFLITE_ABORT abort()
#else
#include "tensorflow/lite/micro/micro_log.h"
inline void AbortImpl() {
DebugLog("HALTED\n");
MicroPrintf("HALTED");
while (1) {
}
}
......
......@@ -269,7 +269,6 @@ cc_library(
copts = micro_copts(),
deps = [
":debug_log",
":micro_string",
],
)
......@@ -291,17 +290,6 @@ cc_library(
],
)
cc_library(
name = "micro_string",
srcs = [
"micro_string.cc",
],
hdrs = [
"micro_string.h",
],
copts = micro_copts(),
)
cc_library(
name = "micro_time",
srcs = [
......@@ -549,17 +537,6 @@ cc_test(
],
)
cc_test(
name = "micro_string_test",
srcs = [
"micro_string_test.cc",
],
deps = [
":micro_string",
"//tensorflow/lite/micro/testing:micro_test",
],
)
cc_test(
name = "micro_time_test",
srcs = [
......
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -19,6 +19,12 @@ limitations under the License.
#include <cstdio>
#include <cstring>
#ifndef TF_LITE_STRIP_ERROR_STRINGS
#include "eyalroz_printf/src/printf/printf.h"
#endif
namespace {
// Print to debug console by default. One can define next to extend destinations
// set: EMSDP_LOG_TO_MEMORY
// : fill .debug_log memory region (data section) with passed chars.
......@@ -89,9 +95,7 @@ void LogToMem(const char* s) {
debug_log_mem[cursor] = '^';
}
extern "C" void DebugLog(const char* s) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
void LogDebugString(const char* s) {
#if defined EMSDP_LOG_TO_UART
DbgUartSendStr(s);
#endif
......@@ -106,6 +110,16 @@ extern "C" void DebugLog(const char* s) {
#warning "EMSDP_LOG_TO_HOST is defined. Ensure hostlib is linked."
fprintf(stderr, "%s", s);
#endif
#endif // TF_LITE_STRIP_ERROR_STRINGS
}
} // namespace
extern "C" void DebugLog(const char* format, va_list args) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
constexpr int kMaxLogLen = 256;
char log_buffer[kMaxLogLen];
vsnprintf_(log_buffer, kMaxLogLen, format, args);
LogDebugString(log_buffer);
#endif
}
\ No newline at end of file
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -15,9 +15,16 @@ limitations under the License.
#include "tensorflow/lite/micro/debug_log.h"
#ifndef TF_LITE_STRIP_ERROR_STRINGS
#include "eyalroz_printf/src/printf/printf.h"
#endif
namespace {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
// For Arm Cortex-M devices, calling SYS_WRITE0 will output the zero-terminated
// string pointed to by R1 to any debug console that's attached to the system.
extern "C" void DebugLog(const char* s) {
void SysWriteDebugConsole(const char* s) {
asm("mov r0, #0x04\n" // SYS_WRITE0
"mov r1, %[str]\n"
"bkpt #0xAB\n"
......@@ -25,3 +32,16 @@ extern "C" void DebugLog(const char* s) {
: [str] "r"(s)
: "r0", "r1");
}
#endif // TF_LITE_STRIP_ERROR_STRINGS
} // namespace
extern "C" void DebugLog(const char* format, va_list args) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
constexpr int kMaxLogLen = 256;
char log_buffer[kMaxLogLen];
vsnprintf_(log_buffer, kMaxLogLen, format, args);
SysWriteDebugConsole(log_buffer);
#endif // TF_LITE_STRIP_ERROR_STRINGS
}
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -17,6 +17,16 @@ limitations under the License.
#include <chre.h>
extern "C" void DebugLog(const char* s) {
chreLog(CHRE_LOG_DEBUG, "[TFL_MICRO] %s", s);
}
#ifndef TF_LITE_STRIP_ERROR_STRINGS
#include "eyalroz_printf/src/printf/printf.h"
#endif
extern "C" void DebugLog(const char* format, va_list args) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
constexpr int kMaxLogLen = 256;
char log_buffer[kMaxLogLen];
vsnprintf_(log_buffer, kMaxLogLen, format, args);
chreLog(CHRE_LOG_DEBUG, "[TFL_MICRO] %s", log_buffer);
#endif
}
\ No newline at end of file
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -24,17 +24,33 @@ extern "C" {
#include "tensorflow/lite/micro/cortex_m_generic/debug_log_callback.h"
#ifndef TF_LITE_STRIP_ERROR_STRINGS
#include "eyalroz_printf/src/printf/printf.h"
#endif
static DebugLogCallback debug_log_callback = nullptr;
namespace {
void InvokeDebugLogCallback(const char* s) {
if (debug_log_callback != nullptr) {
debug_log_callback(s);
}
}
} // namespace
void RegisterDebugLogCallback(void (*cb)(const char* s)) {
debug_log_callback = cb;
}
void DebugLog(const char* s) {
void DebugLog(const char* format, va_list args) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
if (debug_log_callback != nullptr) {
debug_log_callback(s);
}
constexpr int kMaxLogLen = 256;
char log_buffer[kMaxLogLen];
vsnprintf_(log_buffer, kMaxLogLen, format, args);
InvokeDebugLogCallback(log_buffer);
#endif
}
......
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -18,21 +18,17 @@ limitations under the License.
// the only function that's absolutely required to be available on a target
// device, since it's used for communicating test results back to the host so
// that we can verify the implementation is working correctly.
// It's designed to be as easy as possible to supply an implementation though.
// On platforms that have a POSIX stack or C library, it can be written as a
// single call to `fprintf(stderr, "%s", s)` to output a string to the error
// stream of the console, but if there's no OS or C library available, there's
// almost always an equivalent way to write out a string to some serial
// interface that can be used instead. For example on Arm M-series MCUs, calling
// the `bkpt #0xAB` assembler instruction will output the string in r1 to
// whatever debug serial connection is available. If you're running mbed, you
// can do the same by creating `Serial pc(USBTX, USBRX)` and then calling
// `pc.printf("%s", s)`.
// To add an equivalent function for your own platform, create your own
// implementation file, and place it in a subfolder with named after the OS
// you're targeting. For example, see the Cortex M bare metal version in
// tensorflow/lite/micro/bluepill/debug_log.cc or the mbed one on
// tensorflow/lite/micro/mbed/debug_log.cc.
// This function should support standard C/C++ stdio style formatting
// operations. It's designed to be as easy as possible to supply an
// implementation though. On platforms that have a POSIX stack or C library, it
// can be written as a single call to `vfprintf(stderr, format, args)` to output
// a string to the error stream of the console, but if there's no OS or C
// library available, there's almost always an equivalent way to write out a
// string to some serial interface that can be used instead. To add an
// equivalent function for your own platform, create your own implementation
// file, and place it in a subfolder with named after the OS you're targeting.
// For example, see the Cortex M bare metal version in the
// tensorflow/lite/micro/bluepill/debug_log.cc file.
#include "tensorflow/lite/micro/debug_log.h"
......@@ -40,11 +36,11 @@ limitations under the License.
#include <cstdio>
#endif
extern "C" void DebugLog(const char* s) {
extern "C" void DebugLog(const char* format, va_list args) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
// Reusing TF_LITE_STRIP_ERROR_STRINGS to disable DebugLog completely to get
// maximum reduction in binary size. This is because we have DebugLog calls
// via TF_LITE_CHECK that are not stubbed out by TF_LITE_REPORT_ERROR.
fprintf(stderr, "%s", s);
vfprintf(stderr, format, args);
#endif
}
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -15,14 +15,21 @@ limitations under the License.
#ifndef TENSORFLOW_LITE_MICRO_DEBUG_LOG_H_
#define TENSORFLOW_LITE_MICRO_DEBUG_LOG_H_
#ifdef __cplusplus
#include <cstdarg>
#else
#include <stdarg.h>
#endif // __cplusplus
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// This function should be implemented by each target platform, and provide a
// way for strings to be output to some text stream. For more information, see
// tensorflow/lite/micro/debug_log.cc.
void DebugLog(const char* s);
// the tensorflow/lite/micro/debug_log.cc file. This function should support
// standard C/C++ stdio style formatting operations.
void DebugLog(const char* format, va_list args);
#ifdef __cplusplus
} // extern "C"
......
......@@ -100,6 +100,7 @@ TFLMRegistration Register_READ_VARIABLE();
TFLMRegistration Register_REDUCE_MAX();
TFLMRegistration Register_RELU();
TFLMRegistration Register_RELU6();
TFLMRegistration Register_RESHAPE();
TFLMRegistration Register_RESIZE_BILINEAR();
TFLMRegistration Register_RESIZE_NEAREST_NEIGHBOR();
TFLMRegistration Register_RSQRT();
......@@ -137,7 +138,6 @@ TFLMRegistration* Register_WINDOW();
namespace ops {
namespace micro {
TFLMRegistration Register_RESHAPE();
TFLMRegistration Register_ROUND();
} // namespace micro
} // namespace ops
......
......@@ -27,9 +27,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_utils.h"
namespace tflite {
namespace ops {
namespace micro {
namespace reshape {
namespace {
TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
const TfLiteEvalTensor* input =
......@@ -51,13 +49,10 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
return kTfLiteOk;
}
} // namespace reshape
} // namespace
TFLMRegistration Register_RESHAPE() {
return tflite::micro::RegisterOp(nullptr, reshape::PrepareReshapeReference,
reshape::Eval);
return tflite::micro::RegisterOp(nullptr, PrepareReshapeReference, Eval);
}
} // namespace micro
} // namespace ops
} // namespace tflite
......@@ -17,16 +17,10 @@ limitations under the License.
#include "tensorflow/lite/c/common.h"
namespace tflite {
namespace ops {
namespace micro {
namespace reshape {
constexpr int kReshapeInputTensor = 0;
constexpr int kReshapeOutputTensor = 0;
TfLiteStatus PrepareReshapeReference(TfLiteContext* context, TfLiteNode* node);
} // namespace reshape
} // namespace micro
} // namespace ops
} // namespace tflite
......@@ -26,9 +26,6 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_utils.h"
namespace tflite {
namespace ops {
namespace micro {
namespace reshape {
namespace {
......@@ -94,7 +91,4 @@ TfLiteStatus PrepareReshapeReference(TfLiteContext* context, TfLiteNode* node) {
return kTfLiteOk;
}
} // namespace reshape
} // namespace micro
} // namespace ops
} // namespace tflite
......@@ -38,7 +38,7 @@ void ValidateReshapeGoldens(TfLiteTensor* tensors, int tensors_size,
const size_t expected_output_len,
int* expected_dims, const size_t expected_dims_len,
bool expect_failure) {
const TFLMRegistration registration = tflite::ops::micro::Register_RESHAPE();
const TFLMRegistration registration = tflite::Register_RESHAPE();
micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
outputs_array,
/*builtin_data=*/nullptr);
......
......@@ -29,9 +29,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_utils.h"
namespace tflite {
namespace ops {
namespace micro {
namespace reshape {
namespace {
#if defined(VISION_P6)
void* Init(TfLiteContext* context, const char* buffer, size_t length) {
......@@ -91,17 +89,14 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
return kTfLiteOk;
}
} // namespace reshape
} // namespace
TFLMRegistration Register_RESHAPE() {
#if defined(VISION_P6)
return tflite::micro::RegisterOp(reshape::Init, reshape::Prepare,
reshape::Eval);
return tflite::micro::RegisterOp(Init, Prepare, Eval);
#else
return tflite::micro::RegisterOp(nullptr, reshape::Prepare, reshape::Eval);
return tflite::micro::RegisterOp(nullptr, Prepare, Eval);
#endif
}
} // namespace micro
} // namespace ops
} // namespace tflite
/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -24,6 +24,7 @@ limitations under the License.
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/micro/kernels/kernel_util.h"
#include "tensorflow/lite/micro/kernels/reshape.h"
#include "tensorflow/lite/micro/kernels/xtensa/xtensa.h"
#include "tensorflow/lite/micro/kernels/xtensa/xtensa_reshape.h"
......
......@@ -22,9 +22,6 @@ limitations under the License.
namespace tflite {
constexpr int kReshapeInputTensor = 0;
constexpr int kReshapeOutputTensor = 0;
#if defined(VISION_P6)
struct XtensaReshapeData {
......
......@@ -52,7 +52,6 @@ cc_library(
":micro_memory_planner",
"//tensorflow/lite/micro:micro_compatibility",
"//tensorflow/lite/micro:micro_log",
"//tensorflow/lite/micro:micro_string",
],
)
......
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -16,7 +16,6 @@ limitations under the License.
#include "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h"
#include "tensorflow/lite/micro/micro_log.h"
#include "tensorflow/lite/micro/micro_string.h"
namespace tflite {
......
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -23,6 +23,7 @@ limitations under the License.
#include "tensorflow/lite/micro/memory_helpers.h"
#include "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h"
#include "tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.h"
#include "tensorflow/lite/micro/micro_allocator.h"
#include "tensorflow/lite/micro/micro_arena_constants.h"
#include "tensorflow/lite/micro/test_helpers.h"
#include "tensorflow/lite/micro/testing/micro_test.h"
......@@ -913,6 +914,30 @@ TF_LITE_MICRO_TEST(TestAllocatePersistentTfLiteTensor) {
TF_LITE_MICRO_EXPECT_GT(tensor1, tensor2);
}
TF_LITE_MICRO_TEST(TestFailAllocatePersistentTfLiteTensor) {
const tflite::Model* model = tflite::testing::GetSimpleMockModel();
// MicroAllocator::Create always allocates GreedyMemoryPlanner,
// SingleArenaBufferAllocator and MicroAllocator objects.
// Memory available should be <= the sum of the alignments which
// is < sizeof(TfLiteTensor).
constexpr size_t kArenaSize = sizeof(tflite::GreedyMemoryPlanner) +
alignof(tflite::GreedyMemoryPlanner) +
sizeof(tflite::MicroAllocator) +
alignof(tflite::MicroAllocator) +
sizeof(tflite::SingleArenaBufferAllocator) +
alignof(tflite::SingleArenaBufferAllocator) +
tflite::MicroArenaBufferAlignment();
uint8_t arena[kArenaSize];
tflite::MicroAllocator* allocator =
tflite::MicroAllocator::Create(arena, sizeof(arena));
TF_LITE_MICRO_EXPECT(allocator != nullptr);
TfLiteTensor* tensor1 = allocator->AllocatePersistentTfLiteTensor(
model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/1,
/*subgraph_index=*/0);
TF_LITE_MICRO_EXPECT(tensor1 == nullptr);
}
TF_LITE_MICRO_TEST(TestAllocateSingleTempTfLiteTensor) {
const tflite::Model* model = tflite::testing::GetSimpleMockModel();
constexpr size_t arena_size = 1024;
......
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -142,7 +142,7 @@ void MicroContextReportOpError(struct TfLiteContext* context,
const char* format, ...) {
va_list args;
va_start(args, format);
Log(format, args);
VMicroPrintf(format, args);
va_end(args);
}
......
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -17,31 +17,33 @@ limitations under the License.
#include <cstdarg>
#include <cstdint>
#include <new>
#if !defined(TF_LITE_STRIP_ERROR_STRINGS)
#include "tensorflow/lite/micro/debug_log.h"
#include "tensorflow/lite/micro/micro_string.h"
#endif
void Log(const char* format, va_list args) {
#if !defined(TF_LITE_STRIP_ERROR_STRINGS)
// Only pulling in the implementation of this function for builds where we
// expect to make use of it to be extra cautious about not increasing the code
// size.
static constexpr int kMaxLogLen = 256;
char log_buffer[kMaxLogLen];
MicroVsnprintf(log_buffer, kMaxLogLen, format, args);
DebugLog(log_buffer);
DebugLog("\r\n");
#endif
namespace {
void VDebugLog(const char* format, ...) {
va_list args;
va_start(args, format);
DebugLog(format, args);
va_end(args);
}
} // namespace
void VMicroPrintf(const char* format, va_list args) {
DebugLog(format, args);
// TODO(b/290051015): remove "\r\n"
VDebugLog("\r\n");
}
#if !defined(TF_LITE_STRIP_ERROR_STRINGS)
void MicroPrintf(const char* format, ...) {
va_list args;
va_start(args, format);
Log(format, args);
VMicroPrintf(format, args);
va_end(args);
}
#endif
#endif // !defined(TF_LITE_STRIP_ERROR_STRINGS)
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -15,20 +15,17 @@ limitations under the License.
#ifndef TENSORFLOW_LITE_MICRO_MICRO_LOG_H_
#define TENSORFLOW_LITE_MICRO_MICRO_LOG_H_
#include <cstdarg>
// This is a free function used to perform the actual logging.
// This function will be used by MicroPrintf and MicroErrorReporter::Report()
void Log(const char* format, va_list args);
#if !defined(TF_LITE_STRIP_ERROR_STRINGS)
// This function can be used independent of the MicroErrorReporter to get
#include <cstdarg>
// These functions can be used independent of the MicroErrorReporter to get
// printf-like functionalitys and are common to all target platforms.
void MicroPrintf(const char* format, ...);
void VMicroPrintf(const char* format, va_list args);
#else
// We use a #define to ensure that the strings are completely stripped, to
// prevent an unnecessary increase in the binary size.
#define MicroPrintf(...) tflite::Unused(__VA_ARGS__)
#define VMicroPrintf(...) tflite::Unused(__VA_ARGS__)
#endif
namespace tflite {
......@@ -39,6 +36,7 @@ template <typename... Args>
void Unused(Args&&... args) {
(void)(sizeof...(args));
}
} // namespace tflite
#endif // TENSORFLOW_LITE_MICRO_MICRO_LOG_H_
......@@ -429,8 +429,8 @@ class MicroMutableOpResolver : public MicroOpResolver {
}
TfLiteStatus AddReshape() {
return AddBuiltin(BuiltinOperator_RESHAPE,
tflite::ops::micro::Register_RESHAPE(), ParseReshape);
return AddBuiltin(BuiltinOperator_RESHAPE, Register_RESHAPE(),
ParseReshape);
}
TfLiteStatus AddResizeBilinear() {
......
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Implements debug logging for numbers by converting them into strings and then
// calling the main DebugLog(char*) function. These are separated into a
// different file so that platforms can just implement the string output version
// of DebugLog() and then get the numerical variations without requiring any
// more code.
#include "tensorflow/lite/micro/micro_string.h"
#include <cstdarg>
#include <cstdint>
#include <cstring>
namespace {
// Int formats can need up to 10 bytes for the value plus a single byte for the
// sign.
constexpr int kMaxIntCharsNeeded = 10 + 1;
// Hex formats can need up to 8 bytes for the value plus two bytes for the "0x".
constexpr int kMaxHexCharsNeeded = 8 + 2;
// Float formats can need up to 7 bytes for the fraction plus 3 bytes for "x2^"
// plus 3 bytes for the exponent and a single sign bit.
constexpr float kMaxFloatCharsNeeded = 7 + 3 + 3 + 1;
// All input buffers to the number conversion functions must be this long.
const int kFastToBufferSize = 48;
// Reverses a zero-terminated string in-place.
char* ReverseStringInPlace(char* start, char* end) {
char* p1 = start;
char* p2 = end - 1;
while (p1 < p2) {
char tmp = *p1;
*p1++ = *p2;
*p2-- = tmp;
}
return start;
}
// Appends a string to a string, in-place. You need to pass in the maximum
// string length as the second argument.
char* StrCatStr(char* main, int main_max_length, const char* to_append) {
char* current = main;
while (*current != 0) {
++current;
}
char* current_end = main + (main_max_length - 1);
while ((*to_append != 0) && (current < current_end)) {
*current = *to_append;
++current;
++to_append;
}
*current = 0;
return current;
}
// Populates the provided buffer with an ASCII representation of the number.
char* FastUInt32ToBufferLeft(uint32_t i, char* buffer, int base) {
char* start = buffer;
do {
int32_t digit = i % base;
char character;
if (digit < 10) {
character = '0' + digit;
} else {
character = 'a' + (digit - 10);
}
*buffer++ = character;
i /= base;
} while (i > 0);
*buffer = 0;
ReverseStringInPlace(start, buffer);
return buffer;
}
// Populates the provided buffer with an ASCII representation of the number.
char* FastInt32ToBufferLeft(int32_t i, char* buffer) {
uint32_t u = i;
if (i < 0) {
*buffer++ = '-';
u = -u;
}
return FastUInt32ToBufferLeft(u, buffer, 10);
}
// Converts a number to a string and appends it to another.
char* StrCatInt32(char* main, int main_max_length, int32_t number) {
char number_string[kFastToBufferSize];
FastInt32ToBufferLeft(number, number_string);
return StrCatStr(main, main_max_length, number_string);
}
// Converts a number to a string and appends it to another.
char* StrCatUInt32(char* main, int main_max_length, uint32_t number, int base) {
char number_string[kFastToBufferSize];
FastUInt32ToBufferLeft(number, number_string, base);
return StrCatStr(main, main_max_length, number_string);
}
// Populates the provided buffer with ASCII representation of the float number.
// Avoids the use of any floating point instructions (since these aren't
// supported on many microcontrollers) and as a consequence prints values with
// power-of-two exponents.
char* FastFloatToBufferLeft(float f, char* buffer) {
char* current = buffer;
char* current_end = buffer + (kFastToBufferSize - 1);
// Access the bit fields of the floating point value to avoid requiring any
// float instructions. These constants are derived from IEEE 754.
const uint32_t sign_mask = 0x80000000;
const uint32_t exponent_mask = 0x7f800000;
const int32_t exponent_shift = 23;
const int32_t exponent_bias = 127;
const uint32_t fraction_mask = 0x007fffff;
uint32_t u;
memcpy(&u, &f, sizeof(int32_t));
const int32_t exponent =
((u & exponent_mask) >> exponent_shift) - exponent_bias;
const uint32_t fraction = (u & fraction_mask);
// Expect ~0x2B1B9D3 for fraction.
if (u & sign_mask) {
*current = '-';
current += 1;
}
*current = 0;
// These are special cases for infinities and not-a-numbers.
if (exponent == 128) {
if (fraction == 0) {
current = StrCatStr(current, (current_end - current), "Inf");
return current;
} else {
current = StrCatStr(current, (current_end - current), "NaN");
return current;
}
}
// 0x007fffff (8388607) represents 0.99... for the fraction, so to print the
// correct decimal digits we need to scale our value before passing it to the
// conversion function. This scale should be 10000000/8388608 = 1.1920928955.
// We can approximate this using multiply-adds and right-shifts using the
// values in this array. The 1. portion of the number string is printed out
// in a fixed way before the fraction, below.
const int32_t scale_shifts_size = 13;
const int8_t scale_shifts[13] = {3, 4, 8, 11, 13, 14, 17,
18, 19, 20, 21, 22, 23};
uint32_t scaled_fraction = fraction;
for (int i = 0; i < scale_shifts_size; ++i) {
scaled_fraction += (fraction >> scale_shifts[i]);
}
*current = '1';
current += 1;
*current = '.';
current += 1;
*current = 0;
// Prepend leading zeros to fill in all 7 bytes of the fraction. Truncate
// zeros off the end of the fraction. Every fractional value takes 7 bytes.
// For example, 2500 would be written into the buffer as 0002500 since it
// represents .00025.
constexpr int kMaxFractionalDigits = 7;
// Abort early if there is not enough space in the buffer.
if (current_end - current <= kMaxFractionalDigits) {
return current;
}
// Pre-fill buffer with zeros to ensure zero-truncation works properly.
for (int i = 1; i < kMaxFractionalDigits; i++) {
*(current + i) = '0';
}
// Track how large the fraction is to add leading zeros.
char* previous = current;
current = StrCatUInt32(current, (current_end - current), scaled_fraction, 10);
int fraction_digits = current - previous;
int leading_zeros = kMaxFractionalDigits - fraction_digits;
// Overwrite the null terminator from StrCatUInt32 to ensure zero-trunctaion
// works properly.
*current = '0';
// Shift fraction values and prepend zeros if necessary.
if (leading_zeros != 0) {
for (int i = 0; i < fraction_digits; i++) {
current--;
*(current + leading_zeros) = *current;
*current = '0';
}
current += kMaxFractionalDigits;
}
// Truncate trailing zeros for cleaner logs. Ensure we leave at least one
// fractional character for the case when scaled_fraction is 0.
while (*(current - 1) == '0' && (current - 1) > previous) {
current--;
}
*current = 0;
current = StrCatStr(current, (current_end - current), "*2^");
current = StrCatInt32(current, (current_end - current), exponent);
return current;
}
int FormatInt32(char* output, int32_t i) {
return static_cast<int>(FastInt32ToBufferLeft(i, output) - output);
}
int FormatUInt32(char* output, uint32_t i) {
return static_cast<int>(FastUInt32ToBufferLeft(i, output, 10) - output);
}
int FormatHex(char* output, uint32_t i) {
return static_cast<int>(FastUInt32ToBufferLeft(i, output, 16) - output);
}
int FormatFloat(char* output, float i) {
return static_cast<int>(FastFloatToBufferLeft(i, output) - output);
}
} // namespace
extern "C" int MicroVsnprintf(char* output, int len, const char* format,
va_list args) {
int output_index = 0;
const char* current = format;
// One extra character must be left for the null terminator.
const int usable_length = len - 1;
while (*current != '\0' && output_index < usable_length) {
if (*current == '%') {
current++;
switch (*current) {
case 'd':
// Cut off log message if format could exceed log buffer length.
if (usable_length - output_index < kMaxIntCharsNeeded) {
output[output_index++] = '\0';
return output_index;
}
output_index +=
FormatInt32(&output[output_index], va_arg(args, int32_t));
current++;
break;
case 'u':
if (usable_length - output_index < kMaxIntCharsNeeded) {
output[output_index++] = '\0';
return output_index;
}
output_index +=
FormatUInt32(&output[output_index], va_arg(args, uint32_t));
current++;
break;
case 'x':
if (usable_length - output_index < kMaxHexCharsNeeded) {
output[output_index++] = '\0';
return output_index;
}
output[output_index++] = '0';
output[output_index++] = 'x';
output_index +=
FormatHex(&output[output_index], va_arg(args, uint32_t));
current++;
break;
case 'f':
if (usable_length - output_index < kMaxFloatCharsNeeded) {
output[output_index++] = '\0';
return output_index;
}
output_index +=
FormatFloat(&output[output_index], va_arg(args, double));
current++;
break;
case '%':
output[output_index++] = *current++;
break;
case 'c':
if (usable_length - output_index < 1) {
output[output_index++] = '\0';
return output_index;
}
output[output_index++] = va_arg(args, int32_t);
current++;
break;
case 's':
char* string = va_arg(args, char*);
int string_idx = 0;
while (string_idx + output_index < usable_length &&
string[string_idx] != '\0') {
output[output_index++] = string[string_idx++];
}
current++;
}
} else {
output[output_index++] = *current++;
}
}
output[output_index++] = '\0';
return output_index;
}
extern "C" int MicroSnprintf(char* output, int len, const char* format, ...) {
va_list args;
va_start(args, format);
int bytes_written = MicroVsnprintf(output, len, format, args);
va_end(args);
return bytes_written;
}
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_LITE_MICRO_MICRO_STRING_H_
#define TENSORFLOW_LITE_MICRO_MICRO_STRING_H_
#include <cstdarg>
// Implements simple string formatting for numeric types. Returns the number of
// bytes written to output.
extern "C" {
// Functionally equivalent to vsnprintf, trimmed down for TFLite Micro.
// MicroSnprintf() is implemented using MicroVsnprintf().
int MicroVsnprintf(char* output, int len, const char* format, va_list args);
// Functionally equavalent to snprintf, trimmed down for TFLite Micro.
// For example, MicroSnprintf(buffer, 10, "int %d", 10) will put the string
// "int 10" in the buffer.
// Floating point values are logged in exponent notation (1.XXX*2^N).
int MicroSnprintf(char* output, int len, const char* format, ...);
}
#endif // TENSORFLOW_LITE_MICRO_MICRO_STRING_H_
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/micro/micro_string.h"
#include "tensorflow/lite/micro/testing/micro_test.h"
TF_LITE_MICRO_TESTS_BEGIN
TF_LITE_MICRO_TEST(FormatPositiveIntShouldMatchExpected) {
const int kBufferLen = 32;
char buffer[kBufferLen];
const char golden[] = "Int: 55";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Int: %d", 55);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FormatNegativeIntShouldMatchExpected) {
const int kBufferLen = 32;
char buffer[kBufferLen];
const char golden[] = "Int: -55";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Int: %d", -55);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FormatUnsignedIntShouldMatchExpected) {
const int kBufferLen = 32;
char buffer[kBufferLen];
const char golden[] = "UInt: 12345";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "UInt: %u", 12345);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FormatHexShouldMatchExpected) {
const int kBufferLen = 32;
char buffer[kBufferLen];
const char golden[] = "Hex: 0x12345";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Hex: %x", 0x12345);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FormatFloatShouldMatchExpected) {
const int kBufferLen = 32;
char buffer[kBufferLen];
const char golden[] = "Float: 1.0*2^4";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %f", 16.);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FormatCharShouldMatchExpected) {
const int kBufferLen = 32;
char buffer[kBufferLen];
const char golden[] = "Chars: @,Z";
int bytes_written =
MicroSnprintf(buffer, kBufferLen, "Chars: %c,%c", 64, 'Z');
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(BadlyFormattedStringShouldProduceReasonableString) {
const int kBufferLen = 32;
char buffer[kBufferLen];
const char golden[] = "Test Badly % formated % string";
int bytes_written =
MicroSnprintf(buffer, kBufferLen, "Test Badly %% formated %% string%");
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(IntFormatOverrunShouldTruncate) {
const int kBufferLen = 8;
char buffer[kBufferLen];
const char golden[] = "Int: ";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Int: %d", 12345);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(UnsignedIntFormatOverrunShouldTruncate) {
const int kBufferLen = 8;
char buffer[kBufferLen];
const char golden[] = "UInt: ";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "UInt: %u", 12345);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(HexFormatOverrunShouldTruncate) {
const int kBufferLen = 8;
char buffer[kBufferLen];
const char golden[] = "Hex: ";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Hex: %x", 0x12345);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FloatFormatOverrunShouldTruncate) {
const int kBufferLen = 12;
char buffer[kBufferLen];
const char golden[] = "Float: ";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %x", 12345.);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FloatFormatShouldPrintFractionCorrectly) {
const int kBufferLen = 24;
char buffer[kBufferLen];
const char golden[] = "Float: 1.0625*2^0";
// Add small offset to float value to account for float rounding error.
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %f", 1.0625001);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(FloatFormatShouldPrintFractionCorrectlyNoLeadingZeros) {
const int kBufferLen = 24;
char buffer[kBufferLen];
const char golden[] = "Float: 1.6332993*2^-1";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %f", 0.816650);
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(StringFormatOverrunShouldTruncate) {
const int kBufferLen = 10;
char buffer[kBufferLen];
const char golden[] = "String: h";
int bytes_written =
MicroSnprintf(buffer, kBufferLen, "String: %s", "hello world");
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TEST(StringFormatWithExactOutputSizeOverrunShouldTruncate) {
const int kBufferLen = 10;
char buffer[kBufferLen];
const char golden[] = "format st";
int bytes_written = MicroSnprintf(buffer, kBufferLen, "format str");
TF_LITE_MICRO_EXPECT_EQ(static_cast<int>(sizeof(golden)), bytes_written);
TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer);
}
TF_LITE_MICRO_TESTS_END
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -36,7 +36,7 @@ ErrorReporter* GetMicroErrorReporter() {
}
int MicroErrorReporter::Report(const char* format, va_list args) {
Log(format, args);
VMicroPrintf(format, args);
return 0;
}
......
......@@ -80,6 +80,7 @@ DOWNLOADS_DIR := $(MAKEFILE_DIR)/downloads
INCLUDES := \
-I. \
-I$(DOWNLOADS_DIR) \
-I$(DOWNLOADS_DIR)/gemmlowp \
-I$(DOWNLOADS_DIR)/flatbuffers/include \
-I$(DOWNLOADS_DIR)/kissfft \
......@@ -298,7 +299,6 @@ $(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_log_test.cc \
$(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_interpreter_test.cc \
$(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_mutable_op_resolver_test.cc \
$(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_resource_variable_test.cc \
$(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_string_test.cc \
$(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_time_test.cc \
$(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_utils_test.cc \
$(TENSORFLOW_ROOT)tensorflow/lite/micro/recording_micro_allocator_test.cc \
......
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
DOWNLOAD_RESULT := $(shell $(MAKEFILE_DIR)/ext_libs/eyalroz_printf_download.sh $(DOWNLOADS_DIR) $(TENSORFLOW_ROOT))
ifneq ($(DOWNLOAD_RESULT), SUCCESS)
$(error Something went wrong with the printf download: $(DOWNLOAD_RESULT))
endif
PRINTF_PATH := $(DOWNLOADS_DIR)/eyalroz_printf
THIRD_PARTY_CC_SRCS += \
$(PRINTF_PATH)/src/printf/printf.c
THIRD_PARTY_CC_HDRS += \
$(PRINTF_PATH)/src/printf/printf.h
INCLUDES += \
-I$(PRINTF_PATH)/src
#!/bin/bash
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
#
# Called with following arguments:
# 1 - Path to the downloads folder which is typically
# ${TENSORFLOW_ROOT}/tensorflow/lite/micro/tools/make/downloads
# 2 - (optional) TENSORFLOW_ROOT: path to root of the TFLM tree (relative to directory from where the script is called).
#
# This script is called from the Makefile and uses the following convention to
# enable determination of sucess/failure:
#
# - If the script is successful, the only output on stdout should be SUCCESS.
# The makefile checks for this particular string.
#
# - Any string on stdout that is not SUCCESS will be shown in the makefile as
# the cause for the script to have failed.
#
# - Any other informational prints should be on stderr.
set -e
TENSORFLOW_ROOT=${2}
source ${TENSORFLOW_ROOT}tensorflow/lite/micro/tools/make/bash_helpers.sh
DOWNLOADS_DIR=${1}
if [ ! -d ${DOWNLOADS_DIR} ]; then
echo "The top-level downloads directory: ${DOWNLOADS_DIR} does not exist."
exit 1
fi
DOWNLOADED_PRINTF_PATH=${DOWNLOADS_DIR}/eyalroz_printf
if [ -d ${DOWNLOADED_PRINTF_PATH} ]; then
echo >&2 "${DOWNLOADED_PRINTF_PATH} already exists, skipping the download."
else
ZIP_PREFIX="f8ed5a9bd9fa8384430973465e94aa14c925872d"
PRINTF_URL="https://github.com/eyalroz/printf/archive/${ZIP_PREFIX}.zip"
PRINTF_MD5="5772534c1d6f718301bca1fefaba28f3"
# wget is much faster than git clone of the entire repo. So we wget a specific
# version and can then apply a patch, as needed.
wget ${PRINTF_URL} -O /tmp/${ZIP_PREFIX}.zip >&2
check_md5 /tmp/${ZIP_PREFIX}.zip ${PRINTF_MD5}
unzip -qo /tmp/${ZIP_PREFIX}.zip -d /tmp >&2
mv /tmp/printf-${ZIP_PREFIX} ${DOWNLOADED_PRINTF_PATH}
fi
echo "SUCCESS"
\ No newline at end of file
# Copyright 2021 The TensorFlow Authors. All Rights Reserved.
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -26,4 +26,6 @@ $(eval $(call add_third_party_download,$(EMBARC_MLI_PRE_COMPILED_URL),$(EMBARC_M
TCF_FILE = $(PWD)/$(MAKEFILE_DIR)/downloads/$(MLI_LIB_DIR)/hw/emsdp_em11d_em9d_dfss.tcf
include $(MAKEFILE_DIR)/targets/arc/arc_common.inc
\ No newline at end of file
include $(MAKEFILE_DIR)/targets/arc/arc_common.inc
include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
export PATH := $(DOWNLOADS_DIR)/gcc_embedded/bin/:$(PATH)
TARGET_ARCH := cortex-m3
TARGET_TOOLCHAIN_PREFIX := arm-none-eabi-
......@@ -87,3 +102,5 @@ TEST_TARGET_BINARIES = $(shell ls -1 $(BINDIR)/*_test)
test: build
$(TEST_SCRIPT) "$(TEST_TARGET_BINARIES)" $(TEST_PASS_STRING) $(TARGET)
include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc
# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -32,3 +32,5 @@ MICROLITE_CC_KERNEL_SRCS := $(filter-out $(EXCLUDED_CC_SRCS),$(MICROLITE_CC_KERN
MICROLITE_TEST_SRCS := $(filter-out $(EXCLUDED_TESTS),$(MICROLITE_TEST_SRCS))
THIRD_PARTY_CC_HDRS := $(filter-out $(EXCLUDED_HDRS),$(THIRD_PARTY_CC_HDRS))
MICROLITE_CC_HDRS := $(filter-out $(EXCLUDED_KERNEL_HDRS),$(MICROLITE_CC_HDRS))
include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc
# Copyright 2022 The TensorFlow Authors. All Rights Reserved.
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -204,3 +204,5 @@ ifneq ($(TARGET_ARCH), project_generation)
$(TENSORFLOW_ROOT)tensorflow/lite/micro/examples/micro_speech/Makefile.inc
MICRO_LITE_EXAMPLE_TESTS := $(filter-out $(EXCLUDED_EXAMPLE_TESTS), $(MICRO_LITE_EXAMPLE_TESTS))
endif
include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc
# Copyright 2022 The TensorFlow Authors. All Rights Reserved.
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -92,6 +92,13 @@ LIB := $(GENDIR)/libtflm.a
TFLM_CC_SRCS := $(shell find $(TENSORFLOW_ROOT)tensorflow -name "*.cc" -o -name "*.c")
OBJS := $(addprefix $(OBJDIR)/, $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(TFLM_CC_SRCS))))
# if the third party printf library is present, add the include paths
TFLM_PRINTF_PATH := $(shell find third_party -name eyalroz_printf)
ifneq ($(TFLM_PRINTF_PATH),)
INCLUDES += \
-I./third_party
endif
$(OBJDIR)/%.o: %.cc
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
......