From 88ccb5f8f0f8c49a90103b3c81d77d3012984606 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 21 Sep 2021 13:37:32 -0700 Subject: [PATCH] Revert "xtensa: remove unused script" This reverts commit 67d290540e8576e4b996b965b840266d9eb1e29f. The script is actually used to generate the _soc_inthandlers.h file when introducing a new Xtensa SoC. So restore it. Signed-off-by: Daniel Leung --- arch/xtensa/core/xtensa_intgen.py | 140 ++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100755 arch/xtensa/core/xtensa_intgen.py diff --git a/arch/xtensa/core/xtensa_intgen.py b/arch/xtensa/core/xtensa_intgen.py new file mode 100755 index 00000000000..8736e500b7e --- /dev/null +++ b/arch/xtensa/core/xtensa_intgen.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +import re +import fileinput + +# Pass an Xtensa core-isa.h file on stdin or the command line, emits a +# C file on output containing optimized interrupt dispatch routines. + +# FIXME: looking at the assembly generated by the ESP-32 toolchain, +# this isn't as optimal as I'd hoped. the individual cases are tested +# using a L32R + BNONE (i.e. a full mask test) instead of a BBSI, and +# the handlers are being invoked with CALL8 instead of CALL4, +# inexplicably wasting four words of stack. Maybe this should be +# emitting assembly instead. Wouldn't be much more complicated and +# would share all the same structure. + +# My manual count of instructions says that a linear search becomes +# faster on average when there are three or fewer bits to test. Would +# be four, if the compiler would generate BBSI instructions. +MAX_TESTS = 3 + +ints_by_lvl = {} + +# print() wrapper that automatically handles indentation levels +cindent = 0 +def cprint(s): + global cindent + if s.endswith(":"): + print(s) + return + if s.find("}") >= 0: + cindent -= 1 + s = cindent*"\t" + s + print(s) + if s.find("{") >= 0: + cindent += 1 + +def emit_int_handler(ints): + if len(ints) <= MAX_TESTS: + for i in ints: + # FIXME: a little work could allow us to extract the + # handler pointer and argument as literals, saving a few + # instructions and avoiding the need to link in + # _sw_isr_table entirely. + cprint("if (mask & BIT(%d)) {" % i) + cprint("mask = BIT(%d);" % i) + cprint("irq = %d;" % i) + cprint("goto handle_irq;") + cprint("}") + else: + half = int(len(ints)/2) + + m = 0 + for i in ints[0:half]: + m |= 1 << i + cprint("if (mask & " + ("0x%x" % (m)) + ") {") + emit_int_handler(ints[0:half]) + cprint("} else {") + emit_int_handler(ints[half:]) + cprint("}") + +######################################################################## + +# Annoyingly need to join lines and remove #-marked annotations. Some +# versions of the preprocessor (ahem, esp32 SDK) like to include +# newlines in the output where the original expressions are expanded +# from 100% single line macros. Slurp it into a single string and +# parse via whitespace. +blob = "" +for l in fileinput.input(): + l = l if l.find("#") < 0 else l[0:l.find("#")] + blob += l.rstrip() + " " + +for match in re.finditer(r'__xtensa_int_level_magic__\s+(\d+)\s+(\d+)', blob): + irq = int(match.group(1)) + lvl = int(match.group(2)) + + if lvl not in ints_by_lvl: + ints_by_lvl[lvl] = [] + + ints_by_lvl[lvl].append(irq) + +cprint("/*") +cprint(" * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.") +cprint(" *") +cprint(" * Functions here are designed to produce efficient code to") +cprint(" * search an Xtensa bitmask of interrupts, inspecting only those bits") +cprint(" * declared to be associated with a given interrupt level. Each") +cprint(" * dispatcher will handle exactly one flagged interrupt, in numerical") +cprint(" * order (low bits first) and will return a mask of that bit that can") +cprint(" * then be cleared by the calling code. Unrecognized bits for the") +cprint(" * level will invoke an error handler.") +cprint(" */") +cprint("") + +# Re-include the core-isa header and be sure our definitions match, for sanity +cprint("#include ") +cprint("#include ") +cprint("#include ") +cprint("") +for l in ints_by_lvl: + for i in ints_by_lvl[l]: + v = "XCHAL_INT" + str(i) + "_LEVEL" + cprint("#if !defined(" + v + ") || " + str(v) + " != " + str(l)) + cprint("#error core-isa.h interrupt level does not match dispatcher!") + cprint("#endif") +cprint("") + +# Populate empty levels just for sanity. The second-to-last interrupt +# level (usually "debug") typically doesn't have any associated +# vectors, but we don't have any way to know that a-prioi. +max = 0 +for lvl in ints_by_lvl: + if lvl > max: + max = lvl + +for lvl in range(0, max+1): + if not lvl in ints_by_lvl: + ints_by_lvl[lvl] = [] + +# Emit the handlers +for lvl in ints_by_lvl: + cprint("static inline int _xtensa_handle_one_int" + str(lvl) + "(unsigned int mask)") + cprint("{") + + if not ints_by_lvl[lvl]: + cprint("return 0;") + cprint("}") + continue + + cprint("int irq;") + print("") + + emit_int_handler(sorted(ints_by_lvl[lvl])) + + cprint("return 0;") + cprint("handle_irq:") + cprint("_sw_isr_table[irq].isr(_sw_isr_table[irq].arg);") + cprint("return mask;") + cprint("}") + cprint("")