diff options
author | Freya Murphy <freya@freyacat.org> | 2025-04-27 15:40:13 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-04-27 15:45:27 -0400 |
commit | 791390dd7ddd79a06eff6766d857d2744c012d75 (patch) | |
tree | 83a1a3488e6263a9250c06eb72047d783ec1f6a7 /user/include/incbin.h | |
parent | convert user.c to use a standard block size (diff) | |
download | comus-791390dd7ddd79a06eff6766d857d2744c012d75.tar.gz comus-791390dd7ddd79a06eff6766d857d2744c012d75.tar.bz2 comus-791390dd7ddd79a06eff6766d857d2744c012d75.zip |
🍎
Diffstat (limited to '')
-rw-r--r-- | user/include/incbin.h | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/user/include/incbin.h b/user/include/incbin.h new file mode 100644 index 0000000..5a72345 --- /dev/null +++ b/user/include/incbin.h @@ -0,0 +1,441 @@ +/** + * @file incbin.h + * @author Dale Weiler + * @brief Utility for including binary files + * + * Facilities for including binary files into the current translation unit and + * making use from them externally in other translation units. + */ +#ifndef INCBIN_HDR +#define INCBIN_HDR +#include <limits.h> +#if defined(__AVX512BW__) || defined(__AVX512CD__) || defined(__AVX512DQ__) || \ + defined(__AVX512ER__) || defined(__AVX512PF__) || defined(__AVX512VL__) || \ + defined(__AVX512F__) +#define INCBIN_ALIGNMENT_INDEX 6 +#elif defined(__AVX__) || defined(__AVX2__) +#define INCBIN_ALIGNMENT_INDEX 5 +#elif defined(__SSE__) || defined(__SSE2__) || defined(__SSE3__) || \ + defined(__SSSE3__) || defined(__SSE4_1__) || defined(__SSE4_2__) || \ + defined(__neon__) || defined(__ARM_NEON) || defined(__ALTIVEC__) +#define INCBIN_ALIGNMENT_INDEX 4 +#elif ULONG_MAX != 0xffffffffu +#define INCBIN_ALIGNMENT_INDEX 3 +#else +#define INCBIN_ALIGNMENT_INDEX 2 +#endif + +/* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */ +#define INCBIN_ALIGN_SHIFT_0 1 +#define INCBIN_ALIGN_SHIFT_1 2 +#define INCBIN_ALIGN_SHIFT_2 4 +#define INCBIN_ALIGN_SHIFT_3 8 +#define INCBIN_ALIGN_SHIFT_4 16 +#define INCBIN_ALIGN_SHIFT_5 32 +#define INCBIN_ALIGN_SHIFT_6 64 + +/* Actual alignment value */ +#define INCBIN_ALIGNMENT \ + INCBIN_CONCATENATE(INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \ + INCBIN_ALIGNMENT_INDEX) + +/* Stringize */ +#define INCBIN_STR(X) #X +#define INCBIN_STRINGIZE(X) INCBIN_STR(X) +/* Concatenate */ +#define INCBIN_CAT(X, Y) X##Y +#define INCBIN_CONCATENATE(X, Y) INCBIN_CAT(X, Y) +/* Deferred macro expansion */ +#define INCBIN_EVAL(X) X +#define INCBIN_INVOKE(N, ...) INCBIN_EVAL(N(__VA_ARGS__)) +/* Variable argument count for overloading by arity */ +#define INCBIN_VA_ARG_COUNTER(_1, _2, _3, N, ...) N +#define INCBIN_VA_ARGC(...) INCBIN_VA_ARG_COUNTER(__VA_ARGS__, 3, 2, 1, 0) + +/* Green Hills uses a different directive for including binary data */ +#if defined(__ghs__) +#if (__ghs_asm == 2) +#define INCBIN_MACRO ".file" +/* Or consider the ".myrawdata" entry in the ld file */ +#else +#define INCBIN_MACRO "\tINCBIN" +#endif +#else +#define INCBIN_MACRO ".incbin" +#endif + +#ifndef _MSC_VER +#define INCBIN_ALIGN __attribute__((aligned(INCBIN_ALIGNMENT))) +#else +#define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT)) +#endif + +#if defined(__arm__) || /* GNU C and RealView */ \ + defined(__arm) || /* Diab */ \ + defined(_ARM) /* ImageCraft */ +#define INCBIN_ARM +#endif + +#ifdef __GNUC__ +/* Utilize .balign where supported */ +#define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" +#define INCBIN_ALIGN_BYTE ".balign 1\n" +#elif defined(INCBIN_ARM) +/* + * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is + * the shift count. This is the value passed to `.align' + */ +#define INCBIN_ALIGN_HOST \ + ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n" +#define INCBIN_ALIGN_BYTE ".align 0\n" +#else +/* We assume other inline assembler's treat `.align' as `.balign' */ +#define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" +#define INCBIN_ALIGN_BYTE ".align 1\n" +#endif + +/* INCBIN_CONST is used by incbin.c generated files */ +#if defined(__cplusplus) +#define INCBIN_EXTERNAL extern "C" +#define INCBIN_CONST extern const +#else +#define INCBIN_EXTERNAL extern +#define INCBIN_CONST const +#endif + +/** + * @brief Optionally override the linker section into which size and data is + * emitted. + * + * @warning If you use this facility, you might have to deal with + * platform-specific linker output section naming on your own. + */ +#if !defined(INCBIN_OUTPUT_SECTION) +#if defined(__APPLE__) +#define INCBIN_OUTPUT_SECTION ".const_data" +#else +#define INCBIN_OUTPUT_SECTION ".rodata" +#endif +#endif + +/** + * @brief Optionally override the linker section into which data is emitted. + * + * @warning If you use this facility, you might have to deal with + * platform-specific linker output section naming on your own. + */ +#if !defined(INCBIN_OUTPUT_DATA_SECTION) +#define INCBIN_OUTPUT_DATA_SECTION INCBIN_OUTPUT_SECTION +#endif + +/** + * @brief Optionally override the linker section into which size is emitted. + * + * @warning If you use this facility, you might have to deal with + * platform-specific linker output section naming on your own. + * + * @note This is useful for Harvard architectures where program memory cannot + * be directly read from the program without special instructions. With this you + * can chose to put the size variable in RAM rather than ROM. + */ +#if !defined(INCBIN_OUTPUT_SIZE_SECTION) +#define INCBIN_OUTPUT_SIZE_SECTION INCBIN_OUTPUT_SECTION +#endif + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#if defined(TARGET_OS_IPHONE) && !defined(INCBIN_SILENCE_BITCODE_WARNING) +#warning \ + "incbin is incompatible with bitcode. Using the library will break upload to App Store if you have bitcode enabled. Add `#define INCBIN_SILENCE_BITCODE_WARNING` before including this header to silence this warning." +#endif +/* The directives are different for Apple branded compilers */ +#define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n" +#define INCBIN_GLOBAL(NAME) \ + ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" +#define INCBIN_INT ".long " +#define INCBIN_MANGLE "_" +#define INCBIN_BYTE ".byte " +#define INCBIN_TYPE(...) +#else +#define INCBIN_SECTION ".section " INCBIN_OUTPUT_SECTION "\n" +#define INCBIN_GLOBAL(NAME) \ + ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" +#if defined(__ghs__) +#define INCBIN_INT ".word " +#else +#define INCBIN_INT ".int " +#endif +#if defined(__USER_LABEL_PREFIX__) +#define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__) +#else +#define INCBIN_MANGLE "" +#endif +#if defined(INCBIN_ARM) +/* On arm assemblers, `@' is used as a line comment token */ +#define INCBIN_TYPE(NAME) \ + ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n" +#elif defined(__MINGW32__) || defined(__MINGW64__) +/* Mingw doesn't support this directive either */ +#define INCBIN_TYPE(NAME) +#else +/* It's safe to use `@' on other architectures */ +#define INCBIN_TYPE(NAME) \ + ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n" +#endif +#define INCBIN_BYTE ".byte " +#endif + +/* List of style types used for symbol names */ +#define INCBIN_STYLE_CAMEL 0 +#define INCBIN_STYLE_SNAKE 1 + +/** + * @brief Specify the prefix to use for symbol names. + * + * @note By default this is "g". + * + * @code + * #define INCBIN_PREFIX incbin + * #include "incbin.h" + * INCBIN(Foo, "foo.txt"); + * + * // Now you have the following symbols instead: + * // const unsigned char incbinFoo<data>[]; + * // const unsigned char *const incbinFoo<end>; + * // const unsigned int incbinFoo<size>; + * @endcode + */ +#if !defined(INCBIN_PREFIX) +#define INCBIN_PREFIX g +#endif + +/** + * @brief Specify the style used for symbol names. + * + * Possible options are + * - INCBIN_STYLE_CAMEL "CamelCase" + * - INCBIN_STYLE_SNAKE "snake_case" + * + * @note By default this is INCBIN_STYLE_CAMEL + * + * @code + * #define INCBIN_STYLE INCBIN_STYLE_SNAKE + * #include "incbin.h" + * INCBIN(foo, "foo.txt"); + * + * // Now you have the following symbols: + * // const unsigned char <prefix>foo_data[]; + * // const unsigned char *const <prefix>foo_end; + * // const unsigned int <prefix>foo_size; + * @endcode + */ +#if !defined(INCBIN_STYLE) +#define INCBIN_STYLE INCBIN_STYLE_CAMEL +#endif + +/* Style lookup tables */ +#define INCBIN_STYLE_0_DATA Data +#define INCBIN_STYLE_0_END End +#define INCBIN_STYLE_0_SIZE Size +#define INCBIN_STYLE_1_DATA _data +#define INCBIN_STYLE_1_END _end +#define INCBIN_STYLE_1_SIZE _size + +/* Style lookup: returning identifier */ +#define INCBIN_STYLE_IDENT(TYPE) \ + INCBIN_CONCATENATE(INCBIN_STYLE_, \ + INCBIN_CONCATENATE(INCBIN_EVAL(INCBIN_STYLE), \ + INCBIN_CONCATENATE(_, TYPE))) + +/* Style lookup: returning string literal */ +#define INCBIN_STYLE_STRING(TYPE) INCBIN_STRINGIZE(INCBIN_STYLE_IDENT(TYPE)) + +/* Generate the global labels by indirectly invoking the macro with our style + * type and concatenating the name against them. */ +#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \ + INCBIN_INVOKE(INCBIN_GLOBAL, \ + INCBIN_CONCATENATE(NAME, \ + INCBIN_INVOKE(INCBIN_STYLE_IDENT, TYPE))) \ + INCBIN_INVOKE(INCBIN_TYPE, \ + INCBIN_CONCATENATE(NAME, \ + INCBIN_INVOKE(INCBIN_STYLE_IDENT, TYPE))) + +/** + * @brief Externally reference binary data included in another translation unit. + * + * Produces three external symbols that reference the binary data included in + * another translation unit. + * + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with + * "Data", as well as "End" and "Size" after. An example is provided below. + * + * @param TYPE Optional array type. Omitting this picks a default of `unsigned char`. + * @param NAME The name given for the binary data + * + * @code + * INCBIN_EXTERN(Foo); + * + * // Now you have the following symbols: + * // extern const unsigned char <prefix>Foo<data>[]; + * // extern const unsigned char *const <prefix>Foo<end>; + * // extern const unsigned int <prefix>Foo<size>; + * @endcode + * + * You may specify a custom optional data type as well as the first argument. + * @code + * INCBIN_EXTERN(custom_type, Foo); + * + * // Now you have the following symbols: + * // extern const custom_type <prefix>Foo<data>[]; + * // extern const custom_type *const <prefix>Foo<end>; + * // extern const unsigned int <prefix>Foo<size>; + * @endcode + */ +#define INCBIN_EXTERN(...) \ + INCBIN_CONCATENATE(INCBIN_EXTERN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__) +#define INCBIN_EXTERN_1(NAME, ...) INCBIN_EXTERN_2(unsigned char, NAME) +#define INCBIN_EXTERN_2(TYPE, NAME) \ + INCBIN_EXTERNAL const INCBIN_ALIGN TYPE INCBIN_CONCATENATE( \ + INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), INCBIN_STYLE_IDENT(DATA))[]; \ + INCBIN_EXTERNAL const INCBIN_ALIGN TYPE *const INCBIN_CONCATENATE( \ + INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), INCBIN_STYLE_IDENT(END)); \ + INCBIN_EXTERNAL const unsigned int INCBIN_CONCATENATE( \ + INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), INCBIN_STYLE_IDENT(SIZE)) + +/** + * @brief Externally reference textual data included in another translation unit. + * + * Produces three external symbols that reference the textual data included in + * another translation unit. + * + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with + * "Data", as well as "End" and "Size" after. An example is provided below. + * + * @param NAME The name given for the textual data + * + * @code + * INCBIN_EXTERN(Foo); + * + * // Now you have the following symbols: + * // extern const char <prefix>Foo<data>[]; + * // extern const char *const <prefix>Foo<end>; + * // extern const unsigned int <prefix>Foo<size>; + * @endcode + */ +#define INCTXT_EXTERN(NAME) INCBIN_EXTERN_2(char, NAME) + +/** + * @brief Include a binary file into the current translation unit. + * + * Includes a binary file into the current translation unit, producing three symbols + * for objects that encode the data and size respectively. + * + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with + * "Data", as well as "End" and "Size" after. An example is provided below. + * + * @param TYPE Optional array type. Omitting this picks a default of `unsigned char`. + * @param NAME The name to associate with this binary data (as an identifier.) + * @param FILENAME The file to include (as a string literal.) + * + * @code + * INCBIN(Icon, "icon.png"); + * + * // Now you have the following symbols: + * // const unsigned char <prefix>Icon<data>[]; + * // const unsigned char *const <prefix>Icon<end>; + * // const unsigned int <prefix>Icon<size>; + * @endcode + * + * You may specify a custom optional data type as well as the first argument. + * These macros are specialized by arity. + * @code + * INCBIN(custom_type, Icon, "icon.png"); + * + * // Now you have the following symbols: + * // const custom_type <prefix>Icon<data>[]; + * // const custom_type *const <prefix>Icon<end>; + * // const unsigned int <prefix>Icon<size>; + * @endcode + * + * @warning This must be used in global scope + * @warning The identifiers may be different if INCBIN_STYLE is not default + * + * To externally reference the data included by this in another translation unit + * please @see INCBIN_EXTERN. + */ +#ifdef _MSC_VER +#define INCBIN(NAME, FILENAME) INCBIN_EXTERN(NAME) +#else +#define INCBIN(...) \ + INCBIN_CONCATENATE(INCBIN_, INCBIN_VA_ARGC(__VA_ARGS__))(__VA_ARGS__) +#if defined(__GNUC__) +#define INCBIN_1(...) \ + _Pragma("GCC error \"Single argument INCBIN not allowed\"") +#elif defined(__clang__) +#define INCBIN_1(...) \ + _Pragma("clang error \"Single argument INCBIN not allowed\"") +#else +#define INCBIN_1(...) /* Cannot do anything here */ +#endif +#define INCBIN_2(NAME, FILENAME) INCBIN_3(unsigned char, NAME, FILENAME) +#define INCBIN_3(TYPE, NAME, FILENAME) \ + INCBIN_COMMON(TYPE, NAME, FILENAME, /* No terminator for binary data */) +#define INCBIN_COMMON(TYPE, NAME, FILENAME, TERMINATOR) \ + __asm__( \ + INCBIN_SECTION INCBIN_GLOBAL_LABELS( \ + NAME, DATA) INCBIN_ALIGN_HOST INCBIN_MANGLE \ + INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING( \ + DATA) ":\n" INCBIN_MACRO " \"" FILENAME "\"\n" TERMINATOR \ + INCBIN_GLOBAL_LABELS(NAME, \ + END) INCBIN_ALIGN_BYTE INCBIN_MANGLE \ + INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING( \ + END) ":\n" INCBIN_BYTE "1\n" INCBIN_GLOBAL_LABELS(NAME, \ + SIZE) \ + INCBIN_ALIGN_HOST INCBIN_MANGLE INCBIN_STRINGIZE( \ + INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" INCBIN_INT \ + INCBIN_MANGLE INCBIN_STRINGIZE( \ + INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " INCBIN_MANGLE \ + INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING( \ + DATA) "\n" INCBIN_ALIGN_HOST ".text\n"); \ + INCBIN_EXTERN(TYPE, NAME) +#endif + +/** + * @brief Include a textual file into the current translation unit. + * + * This behaves the same as INCBIN except it produces char compatible arrays + * and implicitly adds a null-terminator byte, thus the size of data included + * by this is one byte larger than that of INCBIN. + * + * Includes a textual file into the current translation unit, producing three + * symbols for objects that encode the data and size respectively. + * + * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with + * "Data", as well as "End" and "Size" after. An example is provided below. + * + * @param NAME The name to associate with this binary data (as an identifier.) + * @param FILENAME The file to include (as a string literal.) + * + * @code + * INCTXT(Readme, "readme.txt"); + * + * // Now you have the following symbols: + * // const char <prefix>Readme<data>[]; + * // const char *const <prefix>Readme<end>; + * // const unsigned int <prefix>Readme<size>; + * @endcode + * + * @warning This must be used in global scope + * @warning The identifiers may be different if INCBIN_STYLE is not default + * + * To externally reference the data included by this in another translation unit + * please @see INCBIN_EXTERN. + */ +#if defined(_MSC_VER) +#define INCTXT(NAME, FILENAME) INCBIN_EXTERN(NAME) +#else +#define INCTXT(NAME, FILENAME) \ + INCBIN_COMMON(char, NAME, FILENAME, INCBIN_BYTE "0\n") +#endif + +#endif |