mirror of
https://github.com/linux-sunxi/sunxi-tools.git
synced 2024-11-26 19:33:58 +08:00
29d48c3c39
File.exists got removed from Ruby, File.exist should be used instead.
150 lines
5.2 KiB
Ruby
Executable File
150 lines
5.2 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
#
|
|
# (C) Copyright 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
if ARGV.size < 2
|
|
printf("Usage: #{$PROGRAM_NAME} [c_source_input] [marshalled_header_output]\n\n")
|
|
|
|
printf("This script uses an ARM toolchain to compile native ARM code, and then\n")
|
|
printf("automatically generates the necessary wrapper code for calling it from\n")
|
|
printf("the sunxi-fel tool. Executing such compiled pieces of code natively on\n")
|
|
printf("the device may be needed for the performance critical parts.\n")
|
|
|
|
printf("\nExample input file:\n\n")
|
|
printf(" unsigned sum(unsigned a, unsigned b)\n")
|
|
printf(" {\n")
|
|
printf(" return a + b;\n")
|
|
printf(" }\n")
|
|
printf("\n")
|
|
printf("Using this example code inside of sunxi-fel:\n")
|
|
printf("\n")
|
|
printf(" uint32_t a = 1, b = 2, c;\n")
|
|
printf(" aw_fel_remotefunc_prepare_sum(dev, a, b);\n")
|
|
printf(" aw_fel_remotefunc_execute(dev, &c);\n")
|
|
printf(" printf(\"%%d + %%d = %%d\\n\", a, b, c);\n\n")
|
|
|
|
printf("If the returned result is not needed (a void function), then the second\n")
|
|
printf("argument to the 'aw_fel_remotefunc_execute' function can be NULL.\n\n")
|
|
exit(1)
|
|
end
|
|
|
|
def tool_exists(tool_name)
|
|
`which #{tool_name} > /dev/null 2>&1`
|
|
return $?.to_i == 0
|
|
end
|
|
|
|
def parse_stack_usage(filename)
|
|
return unless File.exist?(filename)
|
|
File.read(filename).strip.split("\n").map do |l|
|
|
if l =~ /\:([^\:\s]+)\s+(\d+)\s+(\S+)/
|
|
if $3 != "static"
|
|
abort sprintf("Non-static stack usage for function '%s'\n", $1)
|
|
end
|
|
{function_name: $1, stack_usage: $2.to_i}
|
|
else
|
|
abort sprintf("Failed to parse stack usage information '%s'\n", l.strip)
|
|
end
|
|
end
|
|
end
|
|
|
|
toolchains = [
|
|
"arm-none-eabi-",
|
|
"arm-linux-gnueabihf-",
|
|
"arm-none-linux-gnueabi-",
|
|
"armv7a-hardfloat-linux-gnueabi-",
|
|
]
|
|
|
|
toolchain = toolchains.find { |toolchain| tool_exists("#{toolchain}gcc") }
|
|
abort "Can't find any usable ARM crosscompiler.\n" unless toolchain
|
|
|
|
# Compile the source file
|
|
system("#{toolchain}gcc -c -Os -marm -march=armv5te -mfloat-abi=soft -fstack-usage -fpic -o #{ARGV[0]}.o #{ARGV[0]}")
|
|
exit($?.to_i) if $?.to_i != 0
|
|
|
|
# Read the stack usage information
|
|
stack_usage = parse_stack_usage("#{ARGV[0]}.su")
|
|
if stack_usage.size != 1
|
|
abort sprintf("Expected only one function in the source file, but got %s.\n",
|
|
stack_usage.map {|a| "'" + a[:function_name] + "()'" }.join(", "))
|
|
end
|
|
|
|
`#{toolchain}size -A #{ARGV[0]}.o`.each_line do |l|
|
|
if l =~ /(\S+)\s+(\S+)/
|
|
if ($1 == ".data" || $1 == ".bss" || $1 == ".rodata") && $2.to_i > 0
|
|
abort "Can't have non-empty '.data', '.bss' or '.rodata' section."
|
|
end
|
|
end
|
|
end
|
|
|
|
`#{toolchain}objdump -t #{ARGV[0]}.o`.each_line do |l|
|
|
if l =~ /\*UND\*/
|
|
abort "External references are not allowed: '#{l.strip}'.\n"
|
|
end
|
|
end
|
|
|
|
function_name = stack_usage[0][:function_name]
|
|
|
|
# Read the source file and strip multiline C comments
|
|
sourcefile = File.read(ARGV[0]).gsub(/\/\*.*?\*\//m, "")
|
|
|
|
# Try to find the function and its arguments
|
|
unless sourcefile =~ /#{function_name}\((.*?)\)/m
|
|
abort sprintf("Can't find the function '%s()' in the source file.\n",
|
|
function_name)
|
|
end
|
|
|
|
# Extract the function argument names
|
|
function_args = $1.split(",").map {|a| if a.strip =~ /([^\*\s]+)$/ then $1 end }
|
|
|
|
# Check if there is any return value
|
|
have_retval = !(sourcefile =~ /void\s+#{function_name}/m)
|
|
|
|
###############################################################################
|
|
# Generate output file
|
|
###############################################################################
|
|
|
|
out = File.open(ARGV[1], "w")
|
|
|
|
out.printf("/* Automatically generated, do not edit! */\n\n")
|
|
|
|
out.printf("static void\n")
|
|
funcdecl = sprintf("aw_fel_remotefunc_prepare_#{function_name}(feldev_handle *dev,")
|
|
out.printf("%s\n", funcdecl)
|
|
out.printf("%s", function_args.map {|a|
|
|
" " * funcdecl.index("(") + " uint32_t " + a }.join(",\n"))
|
|
out.printf(")\n{\n")
|
|
|
|
out.printf("\tstatic uint8_t arm_code[] = {\n")
|
|
`#{toolchain}objdump -d #{ARGV[0]}.o`.each_line {|l|
|
|
next unless l =~ /(\h+)\:\s+(\h+)\s+(\S+)\s+([^;]*)/
|
|
addr = $1
|
|
opcode = $2
|
|
p1 = $3
|
|
p2 = $4.strip
|
|
opcode = opcode.scan(/../).map {|a| "0x" + a }.reverse.join(", ")
|
|
out.printf("\t\t%s, /* %4s: %-8s %-34s \x2a/\n", opcode, addr, p1, p2)
|
|
}
|
|
out.printf("\t};\n")
|
|
|
|
out.printf("\tuint32_t args[] = {\n\t\t")
|
|
out.printf("%s\n\t};\n", function_args.join(",\n\t\t"))
|
|
|
|
out.printf("\taw_fel_remotefunc_prepare(dev, %d, arm_code, sizeof(arm_code), %d, args);\n",
|
|
stack_usage[0][:stack_usage], function_args.size)
|
|
|
|
out.printf("}\n")
|