| #!/usr/bin/env fbpython |
| # Copyright (c) Meta Platforms, Inc. and affiliates. |
| # All rights reserved. |
| # |
| # This source code is licensed under the BSD-style license found in the |
| # LICENSE file in the root directory of this source tree. |
| |
| import argparse |
| import csv |
| import io |
| import os |
| import shutil |
| import subprocess |
| import tempfile |
| from pathlib import Path |
| |
| XTENSA_ROOT = os.environ["XTENSA_TOOLCHAIN"] |
| XTENSA_VER = os.environ["TOOLCHAIN_VER"] |
| XTENSA_TOOLS = os.path.join(XTENSA_ROOT, f"{XTENSA_VER}/XtensaTools") |
| XTENSA_SYSTEM = os.path.join(XTENSA_TOOLS, "config") |
| XTENSA_CORE = os.environ["XTENSA_CORE"] |
| |
| |
| def parse_sections(dsp_dir, dsp_exe): |
| """ |
| >>> xt-size dsp_mu_polling_hifi4 --radix=16 -A |
| dsp_mu_polling_hifi4 : |
| section size addr |
| .UserExceptionVector.literal 0x4 0x24000000 |
| .ResetVector.text 0x14c 0x24020000 |
| .WindowVectors.text 0x16c 0x24020400 |
| .Level2InterruptVector.text 0x8 0x2402057c |
| .Level3InterruptVector.text 0x8 0x2402059c |
| .DebugExceptionVector.text 0xc 0x240205bc |
| .NMIExceptionVector.text 0x4 0x240205dc |
| .KernelExceptionVector.text 0x8 0x240205fc |
| .UserExceptionVector.text 0xc 0x2402061c |
| .DoubleExceptionVector.text 0x8 0x2402063c |
| .rodata 0x398 0x200000 |
| .text 0x4c6c 0x2003a0 |
| .clib.data 0x4 0x20500c |
| .rtos.percpu.data 0x310 0x205010 |
| .data 0x880 0x205320 |
| .bss 0x6b8 0x205ba0 |
| .debug_aranges 0x2c8 0x0 |
| .debug_info 0x4367 0x0 |
| .debug_abbrev 0xf54 0x0 |
| .debug_line 0x36e9 0x0 |
| .debug_frame 0x1f4 0x0 |
| .debug_str 0x1986 0x0 |
| .debug_loc 0x15ba 0x0 |
| .xt.prop 0x4a10 0x0 |
| .xt.lit 0x110 0x0 |
| .xtensa.info 0x218 0x0 |
| .comment 0x5f 0x0 |
| .debug_ranges 0x100 0x0 |
| Total 0x1717f |
| """ |
| cmd = f"{XTENSA_TOOLS}/bin/xt-size {dsp_dir}/{dsp_exe} --radix=16 -A" |
| print(f"Executing command:\n {cmd}\n") |
| p = subprocess.run(cmd.split(" "), capture_output=True) |
| print(p.stdout.decode()) |
| lines = p.stdout.decode().strip().split("\n") |
| print(lines) |
| lines = [line for line in lines if line != ""] |
| lines = lines[2:-1] |
| lines = "\n".join(lines) |
| |
| f = io.StringIO(lines) |
| reader = csv.reader(f, delimiter=" ", skipinitialspace=True) |
| ret_list = [(section, int(addr, 16)) for section, size, addr in reader] |
| print(lines) |
| print(ret_list) |
| return ret_list |
| |
| |
| def xt_objcopy_sections(dsp_dir, dsp_exe, output_obj_path, obj_name, sections): |
| xt_objcopy = f"{XTENSA_TOOLS}/bin/xt-objcopy" |
| xtensa_args = f"--xtensa-system={XTENSA_SYSTEM} --xtensa-core={XTENSA_CORE}" |
| |
| cmd = f"{xt_objcopy} {xtensa_args} -O binary {dsp_dir}/{dsp_exe} {output_obj_path}/{obj_name} " |
| cmd += " ".join([f"--only-section={section}" for section in sections]) |
| |
| print(cmd) |
| subprocess.run(cmd.split(" "), check=True) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument("dsp_exe_path", help="Xtensa DSP executable path") |
| parser.add_argument("output_dir", help="output directory") |
| args = parser.parse_args() |
| |
| dsp_exe_dir = os.path.dirname(args.dsp_exe_path) |
| dsp_exe = os.path.basename(args.dsp_exe_path) |
| |
| Path(args.output_dir).mkdir(parents=True, exist_ok=True) |
| |
| sections = parse_sections(dsp_exe_dir, dsp_exe) |
| |
| DATA_SECTION_START = 0x200000 |
| NCACHE_SECTION_START = 0x20060000 |
| TEXT_SECTION_START = 0x24000000 |
| |
| ncache_sections = [ |
| section |
| for section, addr in sections |
| if addr >= NCACHE_SECTION_START and addr < TEXT_SECTION_START |
| ] |
| |
| data_sections = [ |
| section |
| for section, addr in sections |
| if addr < NCACHE_SECTION_START and addr >= DATA_SECTION_START |
| ] |
| |
| text_sections = [ |
| section for section, addr in sections if addr >= TEXT_SECTION_START |
| ] |
| |
| if len(ncache_sections): |
| dirpath = tempfile.mkdtemp() |
| xt_objcopy_sections( |
| dsp_exe_dir, |
| dsp_exe, |
| dirpath, |
| "dsp_ncache_release.bin", |
| ncache_sections, |
| ) |
| # copy files over |
| shutil.copyfile( |
| os.path.join(dirpath, "dsp_ncache_release.bin"), |
| os.path.join(args.output_dir, "dsp_ncache_release.bin"), |
| ) |
| shutil.rmtree(dirpath) |
| |
| dirpath = tempfile.mkdtemp() |
| |
| xt_objcopy_sections( |
| dsp_exe_dir, |
| dsp_exe, |
| dirpath, |
| "dsp_text_release.bin", |
| text_sections, |
| ) |
| |
| # copy files over |
| shutil.copyfile( |
| os.path.join(dirpath, "dsp_text_release.bin"), |
| os.path.join(args.output_dir, "dsp_text_release.bin"), |
| ) |
| shutil.rmtree(dirpath) |
| |
| dirpath = tempfile.mkdtemp() |
| |
| xt_objcopy_sections( |
| dsp_exe_dir, |
| dsp_exe, |
| dirpath, |
| "dsp_data_release.bin", |
| data_sections, |
| ) |
| |
| # copy files over |
| shutil.copyfile( |
| os.path.join(dirpath, "dsp_data_release.bin"), |
| os.path.join(args.output_dir, "dsp_data_release.bin"), |
| ) |
| shutil.rmtree(dirpath) |
| |
| |
| if __name__ == "__main__": |
| main() |