xref: /aosp_15_r20/external/executorch/backends/cadence/utils/post_compilation.py (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1#!/usr/bin/env fbpython
2# Copyright (c) Meta Platforms, Inc. and affiliates.
3# All rights reserved.
4#
5# This source code is licensed under the BSD-style license found in the
6# LICENSE file in the root directory of this source tree.
7
8import argparse
9import csv
10import io
11import os
12import shutil
13import subprocess
14import tempfile
15from pathlib import Path
16
17XTENSA_ROOT = os.environ["XTENSA_TOOLCHAIN"]
18XTENSA_VER = os.environ["TOOLCHAIN_VER"]
19XTENSA_TOOLS = os.path.join(XTENSA_ROOT, f"{XTENSA_VER}/XtensaTools")
20XTENSA_SYSTEM = os.path.join(XTENSA_TOOLS, "config")
21XTENSA_CORE = os.environ["XTENSA_CORE"]
22
23
24def parse_sections(dsp_dir, dsp_exe):
25    """
26    >>> xt-size dsp_mu_polling_hifi4 --radix=16 -A
27    dsp_mu_polling_hifi4  :
28    section                           size         addr
29    .UserExceptionVector.literal       0x4   0x24000000
30    .ResetVector.text                0x14c   0x24020000
31    .WindowVectors.text              0x16c   0x24020400
32    .Level2InterruptVector.text        0x8   0x2402057c
33    .Level3InterruptVector.text        0x8   0x2402059c
34    .DebugExceptionVector.text         0xc   0x240205bc
35    .NMIExceptionVector.text           0x4   0x240205dc
36    .KernelExceptionVector.text        0x8   0x240205fc
37    .UserExceptionVector.text          0xc   0x2402061c
38    .DoubleExceptionVector.text        0x8   0x2402063c
39    .rodata                          0x398     0x200000
40    .text                           0x4c6c     0x2003a0
41    .clib.data                         0x4     0x20500c
42    .rtos.percpu.data                0x310     0x205010
43    .data                            0x880     0x205320
44    .bss                             0x6b8     0x205ba0
45    .debug_aranges                   0x2c8          0x0
46    .debug_info                     0x4367          0x0
47    .debug_abbrev                    0xf54          0x0
48    .debug_line                     0x36e9          0x0
49    .debug_frame                     0x1f4          0x0
50    .debug_str                      0x1986          0x0
51    .debug_loc                      0x15ba          0x0
52    .xt.prop                        0x4a10          0x0
53    .xt.lit                          0x110          0x0
54    .xtensa.info                     0x218          0x0
55    .comment                          0x5f          0x0
56    .debug_ranges                    0x100          0x0
57    Total                          0x1717f
58    """
59    cmd = f"{XTENSA_TOOLS}/bin/xt-size {dsp_dir}/{dsp_exe} --radix=16 -A"
60    print(f"Executing command:\n {cmd}\n")
61    p = subprocess.run(cmd.split(" "), capture_output=True)
62    print(p.stdout.decode())
63    lines = p.stdout.decode().strip().split("\n")
64    print(lines)
65    lines = [line for line in lines if line != ""]
66    lines = lines[2:-1]
67    lines = "\n".join(lines)
68
69    f = io.StringIO(lines)
70    reader = csv.reader(f, delimiter=" ", skipinitialspace=True)
71    ret_list = [(section, int(addr, 16)) for section, size, addr in reader]
72    print(lines)
73    print(ret_list)
74    return ret_list
75
76
77def xt_objcopy_sections(dsp_dir, dsp_exe, output_obj_path, obj_name, sections):
78    xt_objcopy = f"{XTENSA_TOOLS}/bin/xt-objcopy"
79    xtensa_args = f"--xtensa-system={XTENSA_SYSTEM} --xtensa-core={XTENSA_CORE}"
80
81    cmd = f"{xt_objcopy} {xtensa_args} -O binary {dsp_dir}/{dsp_exe} {output_obj_path}/{obj_name} "
82    cmd += " ".join([f"--only-section={section}" for section in sections])
83
84    print(cmd)
85    subprocess.run(cmd.split(" "), check=True)
86
87
88def main():
89    parser = argparse.ArgumentParser()
90    parser.add_argument("dsp_exe_path", help="Xtensa DSP executable path")
91    parser.add_argument("output_dir", help="output directory")
92    args = parser.parse_args()
93
94    dsp_exe_dir = os.path.dirname(args.dsp_exe_path)
95    dsp_exe = os.path.basename(args.dsp_exe_path)
96
97    Path(args.output_dir).mkdir(parents=True, exist_ok=True)
98
99    sections = parse_sections(dsp_exe_dir, dsp_exe)
100
101    DATA_SECTION_START = 0x200000
102    NCACHE_SECTION_START = 0x20060000
103    TEXT_SECTION_START = 0x24000000
104
105    ncache_sections = [
106        section
107        for section, addr in sections
108        if addr >= NCACHE_SECTION_START and addr < TEXT_SECTION_START
109    ]
110
111    data_sections = [
112        section
113        for section, addr in sections
114        if addr < NCACHE_SECTION_START and addr >= DATA_SECTION_START
115    ]
116
117    text_sections = [
118        section for section, addr in sections if addr >= TEXT_SECTION_START
119    ]
120
121    if len(ncache_sections):
122        dirpath = tempfile.mkdtemp()
123        xt_objcopy_sections(
124            dsp_exe_dir,
125            dsp_exe,
126            dirpath,
127            "dsp_ncache_release.bin",
128            ncache_sections,
129        )
130        # copy files over
131        shutil.copyfile(
132            os.path.join(dirpath, "dsp_ncache_release.bin"),
133            os.path.join(args.output_dir, "dsp_ncache_release.bin"),
134        )
135        shutil.rmtree(dirpath)
136
137    dirpath = tempfile.mkdtemp()
138
139    xt_objcopy_sections(
140        dsp_exe_dir,
141        dsp_exe,
142        dirpath,
143        "dsp_text_release.bin",
144        text_sections,
145    )
146
147    # copy files over
148    shutil.copyfile(
149        os.path.join(dirpath, "dsp_text_release.bin"),
150        os.path.join(args.output_dir, "dsp_text_release.bin"),
151    )
152    shutil.rmtree(dirpath)
153
154    dirpath = tempfile.mkdtemp()
155
156    xt_objcopy_sections(
157        dsp_exe_dir,
158        dsp_exe,
159        dirpath,
160        "dsp_data_release.bin",
161        data_sections,
162    )
163
164    # copy files over
165    shutil.copyfile(
166        os.path.join(dirpath, "dsp_data_release.bin"),
167        os.path.join(args.output_dir, "dsp_data_release.bin"),
168    )
169    shutil.rmtree(dirpath)
170
171
172if __name__ == "__main__":
173    main()
174