1#
2# Convert a file (text or binary) into an assembler source file suitable
3# for gcc. Designed to replicate 'objcopy' with more predictable
4# naming, and supports appending a null byte for embedding text as
5# a string.
6#
7# Designed to be run as a script with "cmake -P"
8#
9# Set variables DATA_FILE, SOURCE_FILE, FILE_TYPE when running this.
10#
11# If FILE_TYPE is set to TEXT, a null byte is appended to DATA_FILE's contents
12# before SOURCE_FILE is created.
13#
14# If FILE_TYPE is unset (or any other value), DATA_FILE is copied
15# verbatim into SOURCE_FILE.
16#
17#
18if(NOT DATA_FILE)
19    message(FATAL_ERROR "DATA_FILE for converting must be specified")
20endif()
21
22if(NOT SOURCE_FILE)
23    message(FATAL_ERROR "SOURCE_FILE destination must be specified")
24endif()
25
26file(READ "${DATA_FILE}" data HEX)
27
28string(LENGTH "${data}" data_len)
29math(EXPR data_len "${data_len} / 2")  # 2 hex bytes per byte
30
31if(FILE_TYPE STREQUAL "TEXT")
32    set(data "${data}00")  # null-byte termination
33endif()
34
35## Convert string of raw hex bytes to lines of hex bytes as gcc .byte expressions
36string(REGEX REPLACE "................................" ".byte \\0\n" data "${data}")  # 16 bytes per line
37string(REGEX REPLACE "[^\n]+$" ".byte \\0\n" data "${data}")                           # last line
38string(REGEX REPLACE "[0-9a-f][0-9a-f]" "0x\\0, " data "${data}")                      # hex formatted C bytes
39string(REGEX REPLACE ", \n" "\n" data "${data}")                                       # trim the last comma
40
41# Use source file name as variable name unless VARIABLE_BASENAME is set
42if(NOT VARIABLE_BASENAME)
43    get_filename_component(varname "${DATA_FILE}" NAME)
44else()
45    set(varname "${VARIABLE_BASENAME}")
46endif()
47
48function(append str)
49    file(APPEND "${SOURCE_FILE}" "${str}")
50endfunction()
51
52function(append_line str)
53    append("${str}\n")
54endfunction()
55
56function(make_and_append_identifier str)
57    string(MAKE_C_IDENTIFIER "${str}" symbol)
58    append_line("\n.global ${symbol}")
59    append("${symbol}:")
60    if(${ARGC} GREATER 1) # optional comment
61        append(" /* ${ARGV1} */")
62    endif()
63    append("\n")
64endfunction()
65
66file(WRITE "${SOURCE_FILE}" "/*")
67append_line(" * Data converted from ${DATA_FILE}")
68if(FILE_TYPE STREQUAL "TEXT")
69    append_line(" * (null byte appended)")
70endif()
71append_line(" */")
72
73append_line(".data")
74append_line(".section .rodata.embedded")
75make_and_append_identifier("${varname}")
76make_and_append_identifier("_binary_${varname}_start" "for objcopy compatibility")
77append("${data}")
78make_and_append_identifier("_binary_${varname}_end" "for objcopy compatibility")
79
80append_line("")
81if(FILE_TYPE STREQUAL "TEXT")
82    make_and_append_identifier("${varname}_length" "not including null byte")
83else()
84    make_and_append_identifier("${varname}_length")
85endif()
86append_line(".word ${data_len}")
87