scripts: build: gen_isr_tables: Implement local ISR generation
This commit moves all the functionality related to the current interrupt parser into gen_isr_tables_parser_carrays.py file. The new parser file gen_isr_tables_parser_local.py file is implemented with the new parser that. Additional information added to the generated interrupt header that contains data required by the new parser. Signed-off-by: Radosław Koppel <radoslaw.koppel@nordicsemi.no>
This commit is contained in:
parent
b0c83f328c
commit
0ae48ecb58
|
@ -1228,10 +1228,11 @@ if(CONFIG_GEN_ISR_TABLES)
|
||||||
# isr_tables.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by
|
# isr_tables.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by
|
||||||
# gen_isr_tables.py
|
# gen_isr_tables.py
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT isr_tables.c
|
OUTPUT isr_tables.c isr_tables_vt.ld isr_tables_swi.ld
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
${ZEPHYR_BASE}/scripts/build/gen_isr_tables.py
|
${ZEPHYR_BASE}/scripts/build/gen_isr_tables.py
|
||||||
--output-source isr_tables.c
|
--output-source isr_tables.c
|
||||||
|
--linker-output-files isr_tables_vt.ld isr_tables_swi.ld
|
||||||
--kernel $<TARGET_FILE:${ZEPHYR_LINK_STAGE_EXECUTABLE}>
|
--kernel $<TARGET_FILE:${ZEPHYR_LINK_STAGE_EXECUTABLE}>
|
||||||
--intlist-section .intList
|
--intlist-section .intList
|
||||||
--intlist-section intList
|
--intlist-section intList
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
struct int_list_header {
|
struct int_list_header {
|
||||||
uint32_t table_size;
|
uint32_t table_size;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION)
|
||||||
|
uint32_t swi_table_entry_size;
|
||||||
|
uint32_t shared_isr_table_entry_size;
|
||||||
|
uint32_t shared_isr_client_num_offset;
|
||||||
|
#endif /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These values are not included in the resulting binary, but instead form the
|
/* These values are not included in the resulting binary, but instead form the
|
||||||
|
@ -24,6 +29,13 @@ struct int_list_header {
|
||||||
Z_GENERIC_SECTION(.irq_info) __used struct int_list_header _iheader = {
|
Z_GENERIC_SECTION(.irq_info) __used struct int_list_header _iheader = {
|
||||||
.table_size = IRQ_TABLE_SIZE,
|
.table_size = IRQ_TABLE_SIZE,
|
||||||
.offset = CONFIG_GEN_IRQ_START_VECTOR,
|
.offset = CONFIG_GEN_IRQ_START_VECTOR,
|
||||||
|
#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION)
|
||||||
|
.swi_table_entry_size = sizeof(struct _isr_table_entry),
|
||||||
|
#if IS_ENABLED(CONFIG_SHARED_INTERRUPTS)
|
||||||
|
.shared_isr_table_entry_size = sizeof(struct z_shared_isr_table_entry),
|
||||||
|
.shared_isr_client_num_offset = offsetof(struct z_shared_isr_table_entry, client_num),
|
||||||
|
#endif /* IS_ENABLED(CONFIG_SHARED_INTERRUPTS) */
|
||||||
|
#endif /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These are placeholder tables. They will be replaced by the real tables
|
/* These are placeholder tables. They will be replaced by the real tables
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import struct
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import importlib
|
||||||
from elftools.elf.elffile import ELFFile
|
from elftools.elf.elffile import ELFFile
|
||||||
from elftools.elf.sections import SymbolTableSection
|
from elftools.elf.sections import SymbolTableSection
|
||||||
|
|
||||||
|
@ -44,10 +44,13 @@ class gen_isr_config:
|
||||||
"""
|
"""
|
||||||
# Constants
|
# Constants
|
||||||
__ISR_FLAG_DIRECT = 1 << 0
|
__ISR_FLAG_DIRECT = 1 << 0
|
||||||
__swt_spurious_handler = "((uintptr_t)&z_irq_spurious)"
|
__swt_spurious_handler = "z_irq_spurious"
|
||||||
__swt_shared_handler = "((uintptr_t)&z_shared_isr)"
|
__swt_shared_handler = "z_shared_isr"
|
||||||
__vt_spurious_handler = "z_irq_spurious"
|
__vt_spurious_handler = "z_irq_spurious"
|
||||||
__vt_irq_handler = "_isr_wrapper"
|
__vt_irq_handler = "_isr_wrapper"
|
||||||
|
__shared_array_name = "z_shared_sw_isr_table"
|
||||||
|
__sw_isr_array_name = "_sw_isr_table"
|
||||||
|
__irq_vector_array_name = "_irq_vector_table"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __bm(bits):
|
def __bm(bits):
|
||||||
|
@ -140,6 +143,18 @@ class gen_isr_config:
|
||||||
def vt_default_handler(self):
|
def vt_default_handler(self):
|
||||||
return self.__vt_default_handler
|
return self.__vt_default_handler
|
||||||
|
|
||||||
|
@property
|
||||||
|
def shared_array_name(self):
|
||||||
|
return self.__shared_array_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sw_isr_array_name(self):
|
||||||
|
return self.__sw_isr_array_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def irq_vector_array_name(self):
|
||||||
|
return self.__irq_vector_array_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def int_bits(self):
|
def int_bits(self):
|
||||||
return self.__int_bits
|
return self.__int_bits
|
||||||
|
@ -233,289 +248,6 @@ class gen_isr_config:
|
||||||
return self.check_sym("CONFIG_64BIT")
|
return self.check_sym("CONFIG_64BIT")
|
||||||
|
|
||||||
|
|
||||||
class gen_isr_parser:
|
|
||||||
source_header = """
|
|
||||||
/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */
|
|
||||||
|
|
||||||
#include <zephyr/toolchain.h>
|
|
||||||
#include <zephyr/linker/sections.h>
|
|
||||||
#include <zephyr/sw_isr_table.h>
|
|
||||||
#include <zephyr/arch/cpu.h>
|
|
||||||
|
|
||||||
typedef void (* ISR)(const void *);
|
|
||||||
"""
|
|
||||||
|
|
||||||
source_assembly_header = """
|
|
||||||
#ifndef ARCH_IRQ_VECTOR_JUMP_CODE
|
|
||||||
#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined"
|
|
||||||
#endif
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, intlist_data, config, log):
|
|
||||||
"""Initialize the parser.
|
|
||||||
|
|
||||||
The function prepares parser to work.
|
|
||||||
Parameters:
|
|
||||||
- intlist_data: The binnary data from intlist section
|
|
||||||
- config: The configuration object
|
|
||||||
- log: The logging object, has to have error and debug methods
|
|
||||||
"""
|
|
||||||
self.__config = config
|
|
||||||
self.__log = log
|
|
||||||
intlist = self.__read_intlist(intlist_data)
|
|
||||||
self.__vt, self.__swt, self.__nv = self.__parse_intlist(intlist)
|
|
||||||
|
|
||||||
def __read_intlist(self, intlist_data):
|
|
||||||
"""read a binary file containing the contents of the kernel's .intList
|
|
||||||
section. This is an instance of a header created by
|
|
||||||
include/zephyr/linker/intlist.ld:
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t num_vectors; <- typically CONFIG_NUM_IRQS
|
|
||||||
struct _isr_list isrs[]; <- Usually of smaller size than num_vectors
|
|
||||||
}
|
|
||||||
|
|
||||||
Followed by instances of struct _isr_list created by IRQ_CONNECT()
|
|
||||||
calls:
|
|
||||||
|
|
||||||
struct _isr_list {
|
|
||||||
/** IRQ line number */
|
|
||||||
int32_t irq;
|
|
||||||
/** Flags for this IRQ, see ISR_FLAG_* definitions */
|
|
||||||
int32_t flags;
|
|
||||||
/** ISR to call */
|
|
||||||
void *func;
|
|
||||||
/** Parameter for non-direct IRQs */
|
|
||||||
const void *param;
|
|
||||||
};
|
|
||||||
"""
|
|
||||||
intlist = {}
|
|
||||||
prefix = self.__config.endian_prefix()
|
|
||||||
|
|
||||||
# Extract header and the rest of the data
|
|
||||||
intlist_header_fmt = prefix + "II"
|
|
||||||
header_sz = struct.calcsize(intlist_header_fmt)
|
|
||||||
header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0)
|
|
||||||
self.__log.debug(str(header_raw))
|
|
||||||
|
|
||||||
intlist["num_vectors"] = header_raw[0]
|
|
||||||
intlist["offset"] = header_raw[1]
|
|
||||||
intdata = intlist_data[header_sz:]
|
|
||||||
|
|
||||||
# Extract information about interrupts
|
|
||||||
if self.__config.check_64b():
|
|
||||||
intlist_entry_fmt = prefix + "iiQQ"
|
|
||||||
else:
|
|
||||||
intlist_entry_fmt = prefix + "iiII"
|
|
||||||
|
|
||||||
intlist["interrupts"] = [i for i in
|
|
||||||
struct.iter_unpack(intlist_entry_fmt, intdata)]
|
|
||||||
|
|
||||||
self.__log.debug("Configured interrupt routing")
|
|
||||||
self.__log.debug("handler irq flags param")
|
|
||||||
self.__log.debug("--------------------------")
|
|
||||||
|
|
||||||
for irq in intlist["interrupts"]:
|
|
||||||
self.__log.debug("{0:<10} {1:<3} {2:<3} {3}".format(
|
|
||||||
hex(irq[2]), irq[0], irq[1], hex(irq[3])))
|
|
||||||
|
|
||||||
return intlist
|
|
||||||
|
|
||||||
def __parse_intlist(self, intlist):
|
|
||||||
"""All the intlist data are parsed into swt and vt arrays.
|
|
||||||
|
|
||||||
The vt array is prepared for hardware interrupt table.
|
|
||||||
Every entry in the selected position would contain None or the name of the function pointer
|
|
||||||
(address or string).
|
|
||||||
|
|
||||||
The swt is a little more complex. At every position it would contain an array of parameter and
|
|
||||||
function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry.
|
|
||||||
If empty array is placed on selected position - it means that the application does not implement
|
|
||||||
this interrupt.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- intlist: The preprocessed list of intlist section content (see read_intlist)
|
|
||||||
|
|
||||||
Return:
|
|
||||||
vt, swt - parsed vt and swt arrays (see function description above)
|
|
||||||
"""
|
|
||||||
nvec = intlist["num_vectors"]
|
|
||||||
offset = intlist["offset"]
|
|
||||||
|
|
||||||
if nvec > pow(2, 15):
|
|
||||||
raise ValueError('nvec is too large, check endianness.')
|
|
||||||
|
|
||||||
self.__log.debug('offset is ' + str(offset))
|
|
||||||
self.__log.debug('num_vectors is ' + str(nvec))
|
|
||||||
|
|
||||||
# Set default entries in both tables
|
|
||||||
if not(self.__config.args.sw_isr_table or self.__config.args.vector_table):
|
|
||||||
self.__log.error("one or both of -s or -V needs to be specified on command line")
|
|
||||||
if self.__config.args.vector_table:
|
|
||||||
vt = [None for i in range(nvec)]
|
|
||||||
else:
|
|
||||||
vt = None
|
|
||||||
if self.__config.args.sw_isr_table:
|
|
||||||
swt = [[] for i in range(nvec)]
|
|
||||||
else:
|
|
||||||
swt = None
|
|
||||||
|
|
||||||
# Process intlist and write to the tables created
|
|
||||||
for irq, flags, func, param in intlist["interrupts"]:
|
|
||||||
if not vt:
|
|
||||||
error("Direct Interrupt %d declared with parameter 0x%x "
|
|
||||||
"but no vector table in use"
|
|
||||||
% (irq, param))
|
|
||||||
if self.__config.test_isr_direct(flags):
|
|
||||||
if param != 0:
|
|
||||||
self.__log.error("Direct irq %d declared, but has non-NULL parameter"
|
|
||||||
% irq)
|
|
||||||
if not 0 <= irq - offset < len(vt):
|
|
||||||
self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" %
|
|
||||||
(irq - offset, offset, len(vt) - 1))
|
|
||||||
vt[irq - offset] = func
|
|
||||||
else:
|
|
||||||
# Regular interrupt
|
|
||||||
if not swt:
|
|
||||||
self.__log.error("Regular Interrupt %d declared with parameter 0x%x "
|
|
||||||
"but no SW ISR_TABLE in use"
|
|
||||||
% (irq, param))
|
|
||||||
|
|
||||||
table_index = self.__config.get_swt_table_index(offset, irq)
|
|
||||||
|
|
||||||
if not 0 <= table_index < len(swt):
|
|
||||||
self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" %
|
|
||||||
(table_index, offset, len(swt) - 1))
|
|
||||||
if self.__config.check_shared_interrupts():
|
|
||||||
lst = swt[table_index]
|
|
||||||
if (param, func) in lst:
|
|
||||||
self.__log.error("Attempting to register the same ISR/arg pair twice.")
|
|
||||||
if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"):
|
|
||||||
self.__log.error(f"Reached shared interrupt client limit. Maybe increase"
|
|
||||||
+ f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?")
|
|
||||||
else:
|
|
||||||
if len(swt[table_index]) > 0:
|
|
||||||
self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})"
|
|
||||||
+ f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}"
|
|
||||||
+ "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?"
|
|
||||||
)
|
|
||||||
swt[table_index].append((param, func))
|
|
||||||
|
|
||||||
return vt, swt, nvec
|
|
||||||
|
|
||||||
def __write_code_irq_vector_table(self, fp):
|
|
||||||
fp.write(self.source_assembly_header)
|
|
||||||
|
|
||||||
fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n")
|
|
||||||
for i in range(self.__nv):
|
|
||||||
func = self.__vt[i]
|
|
||||||
|
|
||||||
if func is None:
|
|
||||||
func = self.__config.vt_default_handler
|
|
||||||
|
|
||||||
if isinstance(func, int):
|
|
||||||
func_as_string = self.__config.get_sym_from_addr(func)
|
|
||||||
else:
|
|
||||||
func_as_string = func
|
|
||||||
|
|
||||||
fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string))
|
|
||||||
fp.write("}\n")
|
|
||||||
|
|
||||||
def __write_address_irq_vector_table(self, fp):
|
|
||||||
fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % self.__nv)
|
|
||||||
for i in range(self.__nv):
|
|
||||||
func = self.__vt[i]
|
|
||||||
|
|
||||||
if func is None:
|
|
||||||
func = self.__config.vt_default_handler
|
|
||||||
|
|
||||||
if isinstance(func, int):
|
|
||||||
fp.write("\t{},\n".format(func))
|
|
||||||
else:
|
|
||||||
fp.write("\t((uintptr_t)&{}),\n".format(func))
|
|
||||||
|
|
||||||
fp.write("};\n")
|
|
||||||
|
|
||||||
def __write_shared_table(self, fp):
|
|
||||||
fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table"
|
|
||||||
" z_shared_sw_isr_table[%d] = {\n" % self.__nv)
|
|
||||||
|
|
||||||
for i in range(self.__nv):
|
|
||||||
if self.__swt[i] is None:
|
|
||||||
client_num = 0
|
|
||||||
client_list = None
|
|
||||||
else:
|
|
||||||
client_num = len(self.__swt[i])
|
|
||||||
client_list = self.__swt[i]
|
|
||||||
|
|
||||||
if client_num <= 1:
|
|
||||||
fp.write("\t{ },\n")
|
|
||||||
else:
|
|
||||||
fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ")
|
|
||||||
for j in range(0, client_num):
|
|
||||||
routine = client_list[j][1]
|
|
||||||
arg = client_list[j][0]
|
|
||||||
|
|
||||||
fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, "
|
|
||||||
f".arg = (const void *){hex(arg)} }},")
|
|
||||||
|
|
||||||
fp.write(" },\n},\n")
|
|
||||||
|
|
||||||
fp.write("};\n")
|
|
||||||
|
|
||||||
def write_source(self, fp):
|
|
||||||
fp.write(self.source_header)
|
|
||||||
|
|
||||||
if self.__config.check_shared_interrupts():
|
|
||||||
self.__write_shared_table(fp)
|
|
||||||
|
|
||||||
if self.__vt:
|
|
||||||
if self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS"):
|
|
||||||
self.__write_address_irq_vector_table(fp)
|
|
||||||
elif self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE"):
|
|
||||||
self.__write_code_irq_vector_table(fp)
|
|
||||||
else:
|
|
||||||
self.__log.error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set")
|
|
||||||
|
|
||||||
if not self.__swt:
|
|
||||||
return
|
|
||||||
|
|
||||||
fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n"
|
|
||||||
% self.__nv)
|
|
||||||
|
|
||||||
level2_offset = self.__config.get_irq_baseoffset(2)
|
|
||||||
level3_offset = self.__config.get_irq_baseoffset(3)
|
|
||||||
|
|
||||||
for i in range(self.__nv):
|
|
||||||
if len(self.__swt[i]) == 0:
|
|
||||||
# Not used interrupt
|
|
||||||
param = "0x0"
|
|
||||||
func = self.__config.swt_spurious_handler
|
|
||||||
elif len(self.__swt[i]) == 1:
|
|
||||||
# Single interrupt
|
|
||||||
param = "{0:#x}".format(self.__swt[i][0][0])
|
|
||||||
func = self.__swt[i][0][1]
|
|
||||||
else:
|
|
||||||
# Shared interrupt
|
|
||||||
param = "&z_shared_sw_isr_table[{0}]".format(i)
|
|
||||||
func = self.__config.swt_shared_handler
|
|
||||||
|
|
||||||
if isinstance(func, int):
|
|
||||||
func_as_string = "{0:#x}".format(func)
|
|
||||||
else:
|
|
||||||
func_as_string = func
|
|
||||||
|
|
||||||
if level2_offset is not None and i == level2_offset:
|
|
||||||
fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n".
|
|
||||||
format(level2_offset))
|
|
||||||
if level3_offset is not None and i == level3_offset:
|
|
||||||
fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n".
|
|
||||||
format(level3_offset))
|
|
||||||
|
|
||||||
fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i))
|
|
||||||
fp.write("};\n")
|
|
||||||
|
|
||||||
|
|
||||||
def get_symbols(obj):
|
def get_symbols(obj):
|
||||||
for section in obj.iter_sections():
|
for section in obj.iter_sections():
|
||||||
if isinstance(section, SymbolTableSection):
|
if isinstance(section, SymbolTableSection):
|
||||||
|
@ -554,6 +286,12 @@ def parse_args():
|
||||||
help="Print additional debugging information")
|
help="Print additional debugging information")
|
||||||
parser.add_argument("-o", "--output-source", required=True,
|
parser.add_argument("-o", "--output-source", required=True,
|
||||||
help="Output source file")
|
help="Output source file")
|
||||||
|
parser.add_argument("-l", "--linker-output-files",
|
||||||
|
nargs=2,
|
||||||
|
metavar=("vector_table_link", "software_interrupt_link"),
|
||||||
|
help="Output linker files. "
|
||||||
|
"Used only if CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. "
|
||||||
|
"In other case empty file would be generated.")
|
||||||
parser.add_argument("-k", "--kernel", required=True,
|
parser.add_argument("-k", "--kernel", required=True,
|
||||||
help="Zephyr kernel image")
|
help="Zephyr kernel image")
|
||||||
parser.add_argument("-s", "--sw-isr-table", action="store_true",
|
parser.add_argument("-s", "--sw-isr-table", action="store_true",
|
||||||
|
@ -576,11 +314,31 @@ def main():
|
||||||
config = gen_isr_config(args, get_symbols(kernel), log)
|
config = gen_isr_config(args, get_symbols(kernel), log)
|
||||||
intlist_data = read_intList_sect(kernel, config.get_intlist_snames())
|
intlist_data = read_intList_sect(kernel, config.get_intlist_snames())
|
||||||
|
|
||||||
parser = gen_isr_parser(intlist_data, config, log)
|
if config.check_sym("CONFIG_ISR_TABLES_LOCAL_DECLARATION"):
|
||||||
|
sys.stdout.write(
|
||||||
|
"Warning: The EXPERIMENTAL ISR_TABLES_LOCAL_DECLARATION feature selected\n")
|
||||||
|
parser_module = importlib.import_module('gen_isr_tables_parser_local')
|
||||||
|
parser = parser_module.gen_isr_parser(intlist_data, config, log)
|
||||||
|
else:
|
||||||
|
parser_module = importlib.import_module('gen_isr_tables_parser_carrays')
|
||||||
|
parser = parser_module.gen_isr_parser(intlist_data, config, log)
|
||||||
|
|
||||||
with open(args.output_source, "w") as fp:
|
with open(args.output_source, "w") as fp:
|
||||||
parser.write_source(fp)
|
parser.write_source(fp)
|
||||||
|
|
||||||
|
if args.linker_output_files is not None:
|
||||||
|
with open(args.linker_output_files[0], "w") as fp_vt, \
|
||||||
|
open(args.linker_output_files[1], "w") as fp_swi:
|
||||||
|
if hasattr(parser, 'write_linker_vt'):
|
||||||
|
parser.write_linker_vt(fp_vt)
|
||||||
|
else:
|
||||||
|
log.debug("Chosen parser does not support vector table linker file")
|
||||||
|
fp_vt.write('/* Empty */\n')
|
||||||
|
if hasattr(parser, 'write_linker_swi'):
|
||||||
|
parser.write_linker_swi(fp_swi)
|
||||||
|
else:
|
||||||
|
log.debug("Chosen parser does not support software interrupt linker file")
|
||||||
|
fp_swi.write('/* Empty */\n')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
292
scripts/build/gen_isr_tables_parser_carrays.py
Normal file
292
scripts/build/gen_isr_tables_parser_carrays.py
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Intel Corporation
|
||||||
|
# Copyright (c) 2018 Foundries.io
|
||||||
|
# Copyright (c) 2023 Nordic Semiconductor NA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import struct
|
||||||
|
|
||||||
|
class gen_isr_parser:
|
||||||
|
source_header = """
|
||||||
|
/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */
|
||||||
|
|
||||||
|
#include <zephyr/toolchain.h>
|
||||||
|
#include <zephyr/linker/sections.h>
|
||||||
|
#include <zephyr/sw_isr_table.h>
|
||||||
|
#include <zephyr/arch/cpu.h>
|
||||||
|
|
||||||
|
typedef void (* ISR)(const void *);
|
||||||
|
"""
|
||||||
|
|
||||||
|
source_assembly_header = """
|
||||||
|
#ifndef ARCH_IRQ_VECTOR_JUMP_CODE
|
||||||
|
#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined"
|
||||||
|
#endif
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, intlist_data, config, log):
|
||||||
|
"""Initialize the parser.
|
||||||
|
|
||||||
|
The function prepares parser to work.
|
||||||
|
Parameters:
|
||||||
|
- intlist_data: The binnary data from intlist section
|
||||||
|
- config: The configuration object
|
||||||
|
- log: The logging object, has to have error and debug methods
|
||||||
|
"""
|
||||||
|
self.__config = config
|
||||||
|
self.__log = log
|
||||||
|
intlist = self.__read_intlist(intlist_data)
|
||||||
|
self.__vt, self.__swt, self.__nv = self.__parse_intlist(intlist)
|
||||||
|
|
||||||
|
def __read_intlist(self, intlist_data):
|
||||||
|
"""read a binary file containing the contents of the kernel's .intList
|
||||||
|
section. This is an instance of a header created by
|
||||||
|
include/zephyr/linker/intlist.ld:
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t num_vectors; <- typically CONFIG_NUM_IRQS
|
||||||
|
struct _isr_list isrs[]; <- Usually of smaller size than num_vectors
|
||||||
|
}
|
||||||
|
|
||||||
|
Followed by instances of struct _isr_list created by IRQ_CONNECT()
|
||||||
|
calls:
|
||||||
|
|
||||||
|
struct _isr_list {
|
||||||
|
/** IRQ line number */
|
||||||
|
int32_t irq;
|
||||||
|
/** Flags for this IRQ, see ISR_FLAG_* definitions */
|
||||||
|
int32_t flags;
|
||||||
|
/** ISR to call */
|
||||||
|
void *func;
|
||||||
|
/** Parameter for non-direct IRQs */
|
||||||
|
const void *param;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
intlist = {}
|
||||||
|
prefix = self.__config.endian_prefix()
|
||||||
|
|
||||||
|
# Extract header and the rest of the data
|
||||||
|
intlist_header_fmt = prefix + "II"
|
||||||
|
header_sz = struct.calcsize(intlist_header_fmt)
|
||||||
|
header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0)
|
||||||
|
self.__log.debug(str(header_raw))
|
||||||
|
|
||||||
|
intlist["num_vectors"] = header_raw[0]
|
||||||
|
intlist["offset"] = header_raw[1]
|
||||||
|
intdata = intlist_data[header_sz:]
|
||||||
|
|
||||||
|
# Extract information about interrupts
|
||||||
|
if self.__config.check_64b():
|
||||||
|
intlist_entry_fmt = prefix + "iiQQ"
|
||||||
|
else:
|
||||||
|
intlist_entry_fmt = prefix + "iiII"
|
||||||
|
|
||||||
|
intlist["interrupts"] = [i for i in
|
||||||
|
struct.iter_unpack(intlist_entry_fmt, intdata)]
|
||||||
|
|
||||||
|
self.__log.debug("Configured interrupt routing")
|
||||||
|
self.__log.debug("handler irq flags param")
|
||||||
|
self.__log.debug("--------------------------")
|
||||||
|
|
||||||
|
for irq in intlist["interrupts"]:
|
||||||
|
self.__log.debug("{0:<10} {1:<3} {2:<3} {3}".format(
|
||||||
|
hex(irq[2]), irq[0], irq[1], hex(irq[3])))
|
||||||
|
|
||||||
|
return intlist
|
||||||
|
|
||||||
|
def __parse_intlist(self, intlist):
|
||||||
|
"""All the intlist data are parsed into swt and vt arrays.
|
||||||
|
|
||||||
|
The vt array is prepared for hardware interrupt table.
|
||||||
|
Every entry in the selected position would contain None or the name of the function pointer
|
||||||
|
(address or string).
|
||||||
|
|
||||||
|
The swt is a little more complex. At every position it would contain an array of parameter and
|
||||||
|
function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry.
|
||||||
|
If empty array is placed on selected position - it means that the application does not implement
|
||||||
|
this interrupt.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- intlist: The preprocessed list of intlist section content (see read_intlist)
|
||||||
|
|
||||||
|
Return:
|
||||||
|
vt, swt - parsed vt and swt arrays (see function description above)
|
||||||
|
"""
|
||||||
|
nvec = intlist["num_vectors"]
|
||||||
|
offset = intlist["offset"]
|
||||||
|
|
||||||
|
if nvec > pow(2, 15):
|
||||||
|
raise ValueError('nvec is too large, check endianness.')
|
||||||
|
|
||||||
|
self.__log.debug('offset is ' + str(offset))
|
||||||
|
self.__log.debug('num_vectors is ' + str(nvec))
|
||||||
|
|
||||||
|
# Set default entries in both tables
|
||||||
|
if not(self.__config.args.sw_isr_table or self.__config.args.vector_table):
|
||||||
|
self.__log.error("one or both of -s or -V needs to be specified on command line")
|
||||||
|
if self.__config.args.vector_table:
|
||||||
|
vt = [None for i in range(nvec)]
|
||||||
|
else:
|
||||||
|
vt = None
|
||||||
|
if self.__config.args.sw_isr_table:
|
||||||
|
swt = [[] for i in range(nvec)]
|
||||||
|
else:
|
||||||
|
swt = None
|
||||||
|
|
||||||
|
# Process intlist and write to the tables created
|
||||||
|
for irq, flags, func, param in intlist["interrupts"]:
|
||||||
|
if self.__config.test_isr_direct(flags):
|
||||||
|
if not vt:
|
||||||
|
self.__log.error("Direct Interrupt %d declared with parameter 0x%x "
|
||||||
|
"but no vector table in use"
|
||||||
|
% (irq, param))
|
||||||
|
if param != 0:
|
||||||
|
self.__log.error("Direct irq %d declared, but has non-NULL parameter"
|
||||||
|
% irq)
|
||||||
|
if not 0 <= irq - offset < len(vt):
|
||||||
|
self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d"
|
||||||
|
% (irq - offset, offset, len(vt) - 1))
|
||||||
|
vt[irq - offset] = func
|
||||||
|
else:
|
||||||
|
# Regular interrupt
|
||||||
|
if not swt:
|
||||||
|
self.__log.error("Regular Interrupt %d declared with parameter 0x%x "
|
||||||
|
"but no SW ISR_TABLE in use"
|
||||||
|
% (irq, param))
|
||||||
|
|
||||||
|
table_index = self.__config.get_swt_table_index(offset, irq)
|
||||||
|
|
||||||
|
if not 0 <= table_index < len(swt):
|
||||||
|
self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" %
|
||||||
|
(table_index, offset, len(swt) - 1))
|
||||||
|
if self.__config.check_shared_interrupts():
|
||||||
|
lst = swt[table_index]
|
||||||
|
if (param, func) in lst:
|
||||||
|
self.__log.error("Attempting to register the same ISR/arg pair twice.")
|
||||||
|
if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"):
|
||||||
|
self.__log.error(f"Reached shared interrupt client limit. Maybe increase"
|
||||||
|
+ f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?")
|
||||||
|
else:
|
||||||
|
if len(swt[table_index]) > 0:
|
||||||
|
self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})"
|
||||||
|
+ f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}"
|
||||||
|
+ "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?"
|
||||||
|
)
|
||||||
|
swt[table_index].append((param, func))
|
||||||
|
|
||||||
|
return vt, swt, nvec
|
||||||
|
|
||||||
|
def __write_code_irq_vector_table(self, fp):
|
||||||
|
fp.write(self.source_assembly_header)
|
||||||
|
|
||||||
|
fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n")
|
||||||
|
for i in range(self.__nv):
|
||||||
|
func = self.__vt[i]
|
||||||
|
|
||||||
|
if func is None:
|
||||||
|
func = self.__config.vt_default_handler
|
||||||
|
|
||||||
|
if isinstance(func, int):
|
||||||
|
func_as_string = self.__config.get_sym_from_addr(func)
|
||||||
|
else:
|
||||||
|
func_as_string = func
|
||||||
|
|
||||||
|
fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string))
|
||||||
|
fp.write("}\n")
|
||||||
|
|
||||||
|
def __write_address_irq_vector_table(self, fp):
|
||||||
|
fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % self.__nv)
|
||||||
|
for i in range(self.__nv):
|
||||||
|
func = self.__vt[i]
|
||||||
|
|
||||||
|
if func is None:
|
||||||
|
func = self.__config.vt_default_handler
|
||||||
|
|
||||||
|
if isinstance(func, int):
|
||||||
|
fp.write("\t{},\n".format(func))
|
||||||
|
else:
|
||||||
|
fp.write("\t((uintptr_t)&{}),\n".format(func))
|
||||||
|
|
||||||
|
fp.write("};\n")
|
||||||
|
|
||||||
|
def __write_shared_table(self, fp):
|
||||||
|
fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table"
|
||||||
|
" z_shared_sw_isr_table[%d] = {\n" % self.__nv)
|
||||||
|
|
||||||
|
for i in range(self.__nv):
|
||||||
|
if self.__swt[i] is None:
|
||||||
|
client_num = 0
|
||||||
|
client_list = None
|
||||||
|
else:
|
||||||
|
client_num = len(self.__swt[i])
|
||||||
|
client_list = self.__swt[i]
|
||||||
|
|
||||||
|
if client_num <= 1:
|
||||||
|
fp.write("\t{ },\n")
|
||||||
|
else:
|
||||||
|
fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ")
|
||||||
|
for j in range(0, client_num):
|
||||||
|
routine = client_list[j][1]
|
||||||
|
arg = client_list[j][0]
|
||||||
|
|
||||||
|
fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, "
|
||||||
|
f".arg = (const void *){hex(arg)} }},")
|
||||||
|
|
||||||
|
fp.write(" },\n},\n")
|
||||||
|
|
||||||
|
fp.write("};\n")
|
||||||
|
|
||||||
|
def write_source(self, fp):
|
||||||
|
fp.write(self.source_header)
|
||||||
|
|
||||||
|
if self.__config.check_shared_interrupts():
|
||||||
|
self.__write_shared_table(fp)
|
||||||
|
|
||||||
|
if self.__vt:
|
||||||
|
if self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS"):
|
||||||
|
self.__write_address_irq_vector_table(fp)
|
||||||
|
elif self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE"):
|
||||||
|
self.__write_code_irq_vector_table(fp)
|
||||||
|
else:
|
||||||
|
self.__log.error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set")
|
||||||
|
|
||||||
|
if not self.__swt:
|
||||||
|
return
|
||||||
|
|
||||||
|
fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n"
|
||||||
|
% self.__nv)
|
||||||
|
|
||||||
|
level2_offset = self.__config.get_irq_baseoffset(2)
|
||||||
|
level3_offset = self.__config.get_irq_baseoffset(3)
|
||||||
|
|
||||||
|
for i in range(self.__nv):
|
||||||
|
if len(self.__swt[i]) == 0:
|
||||||
|
# Not used interrupt
|
||||||
|
param = "0x0"
|
||||||
|
func = self.__config.swt_spurious_handler
|
||||||
|
elif len(self.__swt[i]) == 1:
|
||||||
|
# Single interrupt
|
||||||
|
param = "{0:#x}".format(self.__swt[i][0][0])
|
||||||
|
func = self.__swt[i][0][1]
|
||||||
|
else:
|
||||||
|
# Shared interrupt
|
||||||
|
param = "&z_shared_sw_isr_table[{0}]".format(i)
|
||||||
|
func = self.__config.swt_shared_handler
|
||||||
|
|
||||||
|
if isinstance(func, int):
|
||||||
|
func_as_string = "{0:#x}".format(func)
|
||||||
|
else:
|
||||||
|
func_as_string = func
|
||||||
|
|
||||||
|
if level2_offset is not None and i == level2_offset:
|
||||||
|
fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n".
|
||||||
|
format(level2_offset))
|
||||||
|
if level3_offset is not None and i == level3_offset:
|
||||||
|
fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n".
|
||||||
|
format(level3_offset))
|
||||||
|
|
||||||
|
fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i))
|
||||||
|
fp.write("};\n")
|
375
scripts/build/gen_isr_tables_parser_local.py
Normal file
375
scripts/build/gen_isr_tables_parser_local.py
Normal file
|
@ -0,0 +1,375 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Intel Corporation
|
||||||
|
# Copyright (c) 2018 Foundries.io
|
||||||
|
# Copyright (c) 2023 Nordic Semiconductor NA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import struct
|
||||||
|
|
||||||
|
class gen_isr_parser:
|
||||||
|
source_header = """
|
||||||
|
/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */
|
||||||
|
|
||||||
|
#include <zephyr/toolchain.h>
|
||||||
|
#include <zephyr/linker/sections.h>
|
||||||
|
#include <zephyr/sw_isr_table.h>
|
||||||
|
#include <zephyr/arch/cpu.h>
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
shared_isr_table_header = """
|
||||||
|
|
||||||
|
/* For this parser to work, we have to be sure that shared interrupts table entry
|
||||||
|
* and the normal isr table entry have exactly the same layout
|
||||||
|
*/
|
||||||
|
BUILD_ASSERT(sizeof(struct _isr_table_entry)
|
||||||
|
==
|
||||||
|
sizeof(struct z_shared_isr_table_entry),
|
||||||
|
"Shared ISR and ISR table entries layout do not match");
|
||||||
|
BUILD_ASSERT(offsetof(struct _isr_table_entry, arg)
|
||||||
|
==
|
||||||
|
offsetof(struct z_shared_isr_table_entry, arg),
|
||||||
|
"Shared ISR and ISR table entries layout do not match");
|
||||||
|
BUILD_ASSERT(offsetof(struct _isr_table_entry, isr)
|
||||||
|
==
|
||||||
|
offsetof(struct z_shared_isr_table_entry, isr),
|
||||||
|
"Shared ISR and ISR table entries layout do not match");
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, intlist_data, config, log):
|
||||||
|
"""Initialize the parser.
|
||||||
|
|
||||||
|
The function prepares parser to work.
|
||||||
|
Parameters:
|
||||||
|
- intlist_data: The binnary data from intlist section
|
||||||
|
- config: The configuration object
|
||||||
|
- log: The logging object, has to have error and debug methods
|
||||||
|
"""
|
||||||
|
self.__config = config
|
||||||
|
self.__log = log
|
||||||
|
intlist = self.__read_intlist(intlist_data)
|
||||||
|
self.__vt, self.__swt, self.__nv, header = self.__parse_intlist(intlist)
|
||||||
|
self.__swi_table_entry_size = header["swi_table_entry_size"]
|
||||||
|
self.__shared_isr_table_entry_size = header["shared_isr_table_entry_size"]
|
||||||
|
self.__shared_isr_client_num_offset = header["shared_isr_client_num_offset"]
|
||||||
|
|
||||||
|
def __read_intlist(self, intlist_data):
|
||||||
|
"""read an intList section from the elf file.
|
||||||
|
This is version 2 of a header created by include/zephyr/linker/intlist.ld:
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t num_vectors; <- typically CONFIG_NUM_IRQS
|
||||||
|
uint8_t stream[]; <- the stream with the interrupt data
|
||||||
|
};
|
||||||
|
|
||||||
|
The stream is contained from variable length records in a form:
|
||||||
|
|
||||||
|
struct _isr_list_sname {
|
||||||
|
/** IRQ line number */
|
||||||
|
int32_t irq;
|
||||||
|
/** Flags for this IRQ, see ISR_FLAG_* definitions */
|
||||||
|
int32_t flags;
|
||||||
|
/** The section name */
|
||||||
|
const char sname[];
|
||||||
|
};
|
||||||
|
|
||||||
|
The flexible array member here (sname) contains the name of the section where the structure
|
||||||
|
with interrupt data is located.
|
||||||
|
It is always Null-terminated string thus we have to search through the input data for the
|
||||||
|
structure end.
|
||||||
|
|
||||||
|
"""
|
||||||
|
intlist = {}
|
||||||
|
prefix = self.__config.endian_prefix()
|
||||||
|
|
||||||
|
# Extract header and the rest of the data
|
||||||
|
intlist_header_fmt = prefix + "IIIII"
|
||||||
|
header_sz = struct.calcsize(intlist_header_fmt)
|
||||||
|
header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0)
|
||||||
|
self.__log.debug(str(header_raw))
|
||||||
|
|
||||||
|
intlist["num_vectors"] = header_raw[0]
|
||||||
|
intlist["offset"] = header_raw[1]
|
||||||
|
intlist["swi_table_entry_size"] = header_raw[2]
|
||||||
|
intlist["shared_isr_table_entry_size"] = header_raw[3]
|
||||||
|
intlist["shared_isr_client_num_offset"] = header_raw[4]
|
||||||
|
|
||||||
|
intdata = intlist_data[header_sz:]
|
||||||
|
|
||||||
|
# Extract information about interrupts
|
||||||
|
intlist_entry_fmt = prefix + "ii"
|
||||||
|
entry_sz = struct.calcsize(intlist_entry_fmt)
|
||||||
|
intlist["interrupts"] = []
|
||||||
|
|
||||||
|
while len(intdata) > entry_sz:
|
||||||
|
entry_raw = struct.unpack_from(intlist_entry_fmt, intdata, 0)
|
||||||
|
intdata = intdata[entry_sz:]
|
||||||
|
null_idx = intdata.find(0)
|
||||||
|
if null_idx < 0:
|
||||||
|
self.__log.error("Cannot find sname null termination at IRQ{}".format(entry_raw[0]))
|
||||||
|
bname = intdata[:null_idx]
|
||||||
|
# Next structure starts with 4B alignment
|
||||||
|
next_idx = null_idx + 1
|
||||||
|
next_idx = (next_idx + 3) & ~3
|
||||||
|
intdata = intdata[next_idx:]
|
||||||
|
sname = bname.decode()
|
||||||
|
intlist["interrupts"].append([entry_raw[0], entry_raw[1], sname])
|
||||||
|
self.__log.debug("Unpacked IRQ{}, flags: {}, sname: \"{}\"\n".format(
|
||||||
|
entry_raw[0], entry_raw[1], sname))
|
||||||
|
|
||||||
|
# If any data left at the end - it has to be all the way 0 - this is just a check
|
||||||
|
if (len(intdata) and not all([d == 0 for d in intdata])):
|
||||||
|
self.__log.error("Non-zero data found at the end of the intList data.\n")
|
||||||
|
|
||||||
|
self.__log.debug("Configured interrupt routing with linker")
|
||||||
|
self.__log.debug("irq flags sname")
|
||||||
|
self.__log.debug("--------------------------")
|
||||||
|
|
||||||
|
for irq in intlist["interrupts"]:
|
||||||
|
self.__log.debug("{0:<3} {1:<5} {2}".format(
|
||||||
|
hex(irq[0]), irq[1], irq[2]))
|
||||||
|
|
||||||
|
return intlist
|
||||||
|
|
||||||
|
def __parse_intlist(self, intlist):
|
||||||
|
"""All the intlist data are parsed into swt and vt arrays.
|
||||||
|
|
||||||
|
The vt array is prepared for hardware interrupt table.
|
||||||
|
Every entry in the selected position would contain None or the name of the function pointer
|
||||||
|
(address or string).
|
||||||
|
|
||||||
|
The swt is a little more complex. At every position it would contain an array of parameter and
|
||||||
|
function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry.
|
||||||
|
If empty array is placed on selected position - it means that the application does not implement
|
||||||
|
this interrupt.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- intlist: The preprocessed list of intlist section content (see read_intlist)
|
||||||
|
|
||||||
|
Return:
|
||||||
|
vt, swt - parsed vt and swt arrays (see function description above)
|
||||||
|
"""
|
||||||
|
nvec = intlist["num_vectors"]
|
||||||
|
offset = intlist["offset"]
|
||||||
|
header = {
|
||||||
|
"swi_table_entry_size": intlist["swi_table_entry_size"],
|
||||||
|
"shared_isr_table_entry_size": intlist["shared_isr_table_entry_size"],
|
||||||
|
"shared_isr_client_num_offset": intlist["shared_isr_client_num_offset"]
|
||||||
|
}
|
||||||
|
|
||||||
|
if nvec > pow(2, 15):
|
||||||
|
raise ValueError('nvec is too large, check endianness.')
|
||||||
|
|
||||||
|
self.__log.debug('offset is ' + str(offset))
|
||||||
|
self.__log.debug('num_vectors is ' + str(nvec))
|
||||||
|
|
||||||
|
# Set default entries in both tables
|
||||||
|
if not(self.__config.args.sw_isr_table or self.__config.args.vector_table):
|
||||||
|
self.__log.error("one or both of -s or -V needs to be specified on command line")
|
||||||
|
if self.__config.args.vector_table:
|
||||||
|
vt = [None for i in range(nvec)]
|
||||||
|
else:
|
||||||
|
vt = None
|
||||||
|
if self.__config.args.sw_isr_table:
|
||||||
|
swt = [[] for i in range(nvec)]
|
||||||
|
else:
|
||||||
|
swt = None
|
||||||
|
|
||||||
|
# Process intlist and write to the tables created
|
||||||
|
for irq, flags, sname in intlist["interrupts"]:
|
||||||
|
if self.__config.test_isr_direct(flags):
|
||||||
|
if not 0 <= irq - offset < len(vt):
|
||||||
|
self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" %
|
||||||
|
(irq - offset, offset, len(vt) - 1))
|
||||||
|
vt[irq - offset] = sname
|
||||||
|
else:
|
||||||
|
# Regular interrupt
|
||||||
|
if not swt:
|
||||||
|
self.__log.error("Regular Interrupt %d declared with section name %s "
|
||||||
|
"but no SW ISR_TABLE in use"
|
||||||
|
% (irq, sname))
|
||||||
|
|
||||||
|
table_index = self.__config.get_swt_table_index(offset, irq)
|
||||||
|
|
||||||
|
if not 0 <= table_index < len(swt):
|
||||||
|
self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" %
|
||||||
|
(table_index, offset, len(swt) - 1))
|
||||||
|
# Check if the given section name does not repeat outside of current interrupt
|
||||||
|
for i in range(nvec):
|
||||||
|
if i == irq:
|
||||||
|
continue
|
||||||
|
if sname in swt[i]:
|
||||||
|
self.__log.error(("Attempting to register the same section name \"{}\"for" +
|
||||||
|
"different interrupts: {} and {}").format(sname, i, irq))
|
||||||
|
if self.__config.check_shared_interrupts():
|
||||||
|
lst = swt[table_index]
|
||||||
|
if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"):
|
||||||
|
self.__log.error(f"Reached shared interrupt client limit. Maybe increase"
|
||||||
|
+ f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?")
|
||||||
|
else:
|
||||||
|
if len(swt[table_index]) > 0:
|
||||||
|
self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})"
|
||||||
|
+ f"\nExisting section {swt[table_index]}, new section {sname}"
|
||||||
|
+ "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?"
|
||||||
|
)
|
||||||
|
swt[table_index].append(sname)
|
||||||
|
|
||||||
|
return vt, swt, nvec, header
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __irq_spurious_section(irq):
|
||||||
|
return '.irq_spurious.0x{:x}'.format(irq)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __isr_generated_section(irq):
|
||||||
|
return '.isr_generated.0x{:x}'.format(irq)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __shared_entry_section(irq, ent):
|
||||||
|
return '.isr_shared.0x{:x}_0x{:x}'.format(irq, ent)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __shared_client_num_section(irq):
|
||||||
|
return '.isr_shared.0x{:x}_client_num'.format(irq)
|
||||||
|
|
||||||
|
def __isr_spurious_entry(self, irq):
|
||||||
|
return '_Z_ISR_TABLE_ENTRY({irq}, {func}, NULL, "{sect}");'.format(
|
||||||
|
irq = irq,
|
||||||
|
func = self.__config.swt_spurious_handler,
|
||||||
|
sect = self.__isr_generated_section(irq)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __isr_shared_entry(self, irq):
|
||||||
|
return '_Z_ISR_TABLE_ENTRY({irq}, {func}, {arg}, "{sect}");'.format(
|
||||||
|
irq = irq,
|
||||||
|
arg = '&{}[{}]'.format(self.__config.shared_array_name, irq),
|
||||||
|
func = self.__config.swt_shared_handler,
|
||||||
|
sect = self.__isr_generated_section(irq)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __irq_spurious_entry(self, irq):
|
||||||
|
return '_Z_ISR_DIRECT_TABLE_ENTRY({irq}, {func}, "{sect}");'.format(
|
||||||
|
irq = irq,
|
||||||
|
func = self.__config.vt_default_handler,
|
||||||
|
sect = self.__irq_spurious_section(irq)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __write_isr_handlers(self, fp):
|
||||||
|
for i in range(self.__nv):
|
||||||
|
if len(self.__swt[i]) <= 0:
|
||||||
|
fp.write(self.__isr_spurious_entry(i) + '\n')
|
||||||
|
elif len(self.__swt[i]) > 1:
|
||||||
|
# Connect to shared handlers
|
||||||
|
fp.write(self.__isr_shared_entry(i) + '\n')
|
||||||
|
else:
|
||||||
|
fp.write('/* ISR: {} implemented in app in "{}" section. */\n'.format(
|
||||||
|
i, self.__swt[i][0]))
|
||||||
|
|
||||||
|
def __write_irq_handlers(self, fp):
|
||||||
|
for i in range(self.__nv):
|
||||||
|
if self.__vt[i] is None:
|
||||||
|
fp.write(self.__irq_spurious_entry(i) + '\n')
|
||||||
|
else:
|
||||||
|
fp.write('/* ISR: {} implemented in app. */\n'.format(i))
|
||||||
|
|
||||||
|
def __write_shared_handlers(self, fp):
|
||||||
|
fp.write("extern struct z_shared_isr_table_entry "
|
||||||
|
"{}[{}];\n".format(self.__config.shared_array_name, self.__nv))
|
||||||
|
|
||||||
|
shared_cnt = self.__config.get_sym('CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS')
|
||||||
|
for i in range(self.__nv):
|
||||||
|
swt_len = len(self.__swt[i])
|
||||||
|
for j in range(shared_cnt):
|
||||||
|
if (swt_len <= 1) or (swt_len <= j):
|
||||||
|
# Add all unused entry
|
||||||
|
fp.write('static Z_DECL_ALIGN(struct _isr_table_entry)\n' +
|
||||||
|
'\tZ_GENERIC_SECTION({})\n'.format(self.__shared_entry_section(i, j)) +
|
||||||
|
'\t__used isr_shared_empty_entry_0x{:x}_0x{:x} = {{\n'.format(i, j) +
|
||||||
|
'\t\t.arg = (const void *)NULL,\n' +
|
||||||
|
'\t\t.isr = (void (*)(const void *))(void *)0\n' +
|
||||||
|
'};\n'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Add information about entry implemented by application
|
||||||
|
fp.write('/* Shared isr {} entry {} implemented in "{}" section*/\n'.format(
|
||||||
|
i, j, self.__swt[i][j]))
|
||||||
|
|
||||||
|
# Add information about clients count
|
||||||
|
fp.write(('static size_t Z_GENERIC_SECTION({}) __used\n' +
|
||||||
|
'isr_shared_client_num_0x{:x} = {};\n\n').format(
|
||||||
|
self.__shared_client_num_section(i),
|
||||||
|
i,
|
||||||
|
0 if swt_len < 2 else swt_len)
|
||||||
|
)
|
||||||
|
|
||||||
|
def write_source(self, fp):
|
||||||
|
fp.write(self.source_header)
|
||||||
|
|
||||||
|
if self.__vt:
|
||||||
|
self.__write_irq_handlers(fp)
|
||||||
|
|
||||||
|
if not self.__swt:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.__config.check_shared_interrupts():
|
||||||
|
self.__write_shared_handlers(fp)
|
||||||
|
|
||||||
|
self.__write_isr_handlers(fp)
|
||||||
|
|
||||||
|
def __write_linker_irq(self, fp):
|
||||||
|
fp.write('{} = .;\n'.format(self.__config.irq_vector_array_name))
|
||||||
|
for i in range(self.__nv):
|
||||||
|
if self.__vt[i] is None:
|
||||||
|
sname = self.__irq_spurious_section(i)
|
||||||
|
else:
|
||||||
|
sname = self.__vt[i]
|
||||||
|
fp.write('KEEP(*("{}"))\n'.format(sname))
|
||||||
|
|
||||||
|
def __write_linker_shared(self, fp):
|
||||||
|
fp.write(". = ALIGN({});\n".format(self.__shared_isr_table_entry_size))
|
||||||
|
fp.write('{} = .;\n'.format(self.__config.shared_array_name))
|
||||||
|
shared_cnt = self.__config.get_sym('CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS')
|
||||||
|
client_num_pads = self.__shared_isr_client_num_offset - \
|
||||||
|
shared_cnt * self.__swi_table_entry_size
|
||||||
|
if client_num_pads < 0:
|
||||||
|
self.__log.error("Invalid __shared_isr_client_num_offset header value")
|
||||||
|
for i in range(self.__nv):
|
||||||
|
swt_len = len(self.__swt[i])
|
||||||
|
# Add all entries
|
||||||
|
for j in range(shared_cnt):
|
||||||
|
if (swt_len <= 1) or (swt_len <= j):
|
||||||
|
fp.write('KEEP(*("{}"))\n'.format(self.__shared_entry_section(i, j)))
|
||||||
|
else:
|
||||||
|
sname = self.__swt[i][j]
|
||||||
|
if (j != 0) and (sname in self.__swt[i][0:j]):
|
||||||
|
fp.write('/* Repetition of "{}" section */\n'.format(sname))
|
||||||
|
else:
|
||||||
|
fp.write('KEEP(*("{}"))\n'.format(sname))
|
||||||
|
fp.write('. = . + {};\n'.format(client_num_pads))
|
||||||
|
fp.write('KEEP(*("{}"))\n'.format(self.__shared_client_num_section(i)))
|
||||||
|
fp.write(". = ALIGN({});\n".format(self.__shared_isr_table_entry_size))
|
||||||
|
|
||||||
|
def __write_linker_isr(self, fp):
|
||||||
|
fp.write(". = ALIGN({});\n".format(self.__swi_table_entry_size))
|
||||||
|
fp.write('{} = .;\n'.format(self.__config.sw_isr_array_name))
|
||||||
|
for i in range(self.__nv):
|
||||||
|
if (len(self.__swt[i])) == 1:
|
||||||
|
sname = self.__swt[i][0]
|
||||||
|
else:
|
||||||
|
sname = self.__isr_generated_section(i)
|
||||||
|
fp.write('KEEP(*("{}"))\n'.format(sname))
|
||||||
|
|
||||||
|
def write_linker_vt(self, fp):
|
||||||
|
if self.__vt:
|
||||||
|
self.__write_linker_irq(fp)
|
||||||
|
|
||||||
|
def write_linker_swi(self, fp):
|
||||||
|
if self.__swt:
|
||||||
|
self.__write_linker_isr(fp)
|
||||||
|
|
||||||
|
if self.__config.check_shared_interrupts():
|
||||||
|
self.__write_linker_shared(fp)
|
Loading…
Reference in a new issue