mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
refactor(ulp): make the ULP subproject directory explicit
components/ulp/cmake holds the project that builds a ULP program. Name it subproject, as the bootloader does.
This commit is contained in:
Executable
+166
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python
|
||||
# SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# esp32ulp_mapgen utility converts a symbol list provided by nm into an export script
|
||||
# for the linker and a header file.
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import textwrap
|
||||
import typing
|
||||
|
||||
UTIL = os.path.basename(__file__)
|
||||
|
||||
|
||||
def name_mangling(name: str) -> str:
|
||||
# Simple and dumb name mangling for namespaced name following GCC algorithm
|
||||
ns, n = name.split('::')
|
||||
return f'_ZN{len(ns)}{ns}{len(n)}{n}E'
|
||||
|
||||
|
||||
# On ESP32-P4 the LP CPU accesses HP SRAM via the L2 cache at the same
|
||||
# address as the HP CPU cacheable alias. The HP application should access
|
||||
# LP Core variables through the non-cacheable alias to avoid coherency
|
||||
# issues with the LP CPU. The non-cacheable alias is obtained by adding
|
||||
# the offset 0x40000000 to addresses below 0x50000000.
|
||||
_P4_NON_CACHEABLE_OFFSET = 0x40000000
|
||||
_P4_LP_RAM_BASE = 0x50000000
|
||||
|
||||
|
||||
def map_to_hp_cpu_addr(addr: int, target: str | None) -> int:
|
||||
"""Translate an LP-CPU VMA to the address the HP CPU should use to access it."""
|
||||
if target == 'esp32p4' and addr < _P4_LP_RAM_BASE:
|
||||
return addr + _P4_NON_CACHEABLE_OFFSET
|
||||
return addr
|
||||
|
||||
|
||||
def gen_ld_h_from_sym(
|
||||
f_sym: typing.TextIO,
|
||||
f_ld: typing.TextIO,
|
||||
f_h: typing.TextIO,
|
||||
base_addr: int,
|
||||
prefix: str,
|
||||
target: str | None = None,
|
||||
) -> None:
|
||||
f_ld.write(
|
||||
textwrap.dedent(
|
||||
f"""
|
||||
/* ULP variable definitions for the linker.
|
||||
* This file is generated automatically by {UTIL} utility.
|
||||
*/
|
||||
""" # noqa: E222
|
||||
)
|
||||
)
|
||||
cpp_mode = False
|
||||
var_prefix = prefix
|
||||
namespace = ''
|
||||
if '::' in prefix:
|
||||
# C++ mode, let's avoid the extern "C" type and instead use namespace
|
||||
f_h.write(
|
||||
textwrap.dedent(
|
||||
f"""
|
||||
/* ULP variable definitions for the compiler.
|
||||
* This file is generated automatically by {UTIL} utility.
|
||||
*/
|
||||
#pragma once
|
||||
""" # noqa: E222
|
||||
)
|
||||
)
|
||||
tmp = prefix.split('::')
|
||||
namespace = tmp[0]
|
||||
var_prefix = '_'.join(tmp[1:]) # Limit to a single namespace here to avoid complex mangling rules
|
||||
f_h.write(f'namespace {namespace} {{\n')
|
||||
cpp_mode = True
|
||||
else:
|
||||
f_h.write(
|
||||
textwrap.dedent(
|
||||
f"""
|
||||
/* ULP variable definitions for the compiler.
|
||||
* This file is generated automatically by {UTIL} utility.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {{
|
||||
#endif\n
|
||||
""" # noqa: E222
|
||||
)
|
||||
)
|
||||
|
||||
# Format the regular expression to match the readelf output
|
||||
expr = re.compile(
|
||||
r'^.*(?P<address>[a-f0-9]{8})\s+(?P<size>\d+) (OBJECT|NOTYPE)\s+GLOBAL\s+DEFAULT\s+[^ ]+ (?P<name>.*)$'
|
||||
)
|
||||
for line in f_sym:
|
||||
# readelf format output has the following structure:
|
||||
# Num: Value Size Type Bind Vis Ndx Name
|
||||
# So match the line with a regular expression to parse it first
|
||||
groups = expr.match(line)
|
||||
|
||||
# Ignore lines that do not match the expected format such as non global symbols
|
||||
if groups is None:
|
||||
continue
|
||||
|
||||
# Extract the symbol information
|
||||
addr = map_to_hp_cpu_addr(int(groups.group('address'), 16) + base_addr, target)
|
||||
size = int(groups.group('size'))
|
||||
sym_name = groups.group('name')
|
||||
|
||||
# Add the variable prefix if provided
|
||||
var_name = var_prefix + sym_name
|
||||
|
||||
# Get the dimension of the variable if it is an array
|
||||
var_dimension = f'[{size // 4}]' if size > 4 else '' # Use // to automatically perform an integer division
|
||||
|
||||
# Write the variable definition to the header file and the address to the linker script
|
||||
f_h.write(f'extern uint32_t {var_name}{var_dimension};\n')
|
||||
|
||||
name_in_ld = name_mangling(namespace + '::' + var_name) if cpp_mode else var_name
|
||||
f_ld.write(f'{name_in_ld} = 0x{addr:08x};\n')
|
||||
|
||||
if cpp_mode:
|
||||
f_h.write('}\n')
|
||||
else:
|
||||
f_h.write(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
description = (
|
||||
'This application generates .h and .ld files for symbols defined in input file. '
|
||||
'The input symbols file can be generated using readelf utility like this: '
|
||||
'<PREFIX>readelf -sW <elf_file> > <symbols_file>'
|
||||
)
|
||||
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument(
|
||||
'-s', '--symfile', required=True, help='symbols file name', metavar='SYMFILE', type=argparse.FileType('r')
|
||||
)
|
||||
parser.add_argument(
|
||||
'-o', '--outputfile', required=True, help='destination .h and .ld files name prefix', metavar='OUTFILE'
|
||||
)
|
||||
parser.add_argument('--base-addr', required=True, help='base address of the ULP memory, to be added to each symbol')
|
||||
parser.add_argument('-p', '--prefix', required=False, help='prefix for generated header file', default='ulp_')
|
||||
parser.add_argument(
|
||||
'--target',
|
||||
required=False,
|
||||
help='IDF target chip name (e.g. esp32p4), used for address translation',
|
||||
default=None,
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.outputfile + '.h', 'w') as f_h, open(args.outputfile + '.ld', 'w') as f_ld:
|
||||
gen_ld_h_from_sym(args.symfile, f_ld, f_h, int(args.base_addr, 0), args.prefix, args.target)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user