#!/usr/bin/env python3 # Copyright (C) 2020 Inria # # This file is subject to the terms and conditions of the GNU Lesser # General Public License v2.1. See the file LICENSE in the top level # directory for more details. """Generate the vectors table for a given STM32 CPU line.""" import os import argparse import re CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) RIOTBASE = os.getenv( "RIOTBASE", os.path.abspath(os.path.join(CURRENT_DIR, "../../../.."))) STM32_VECTORS_DIR = os.path.join(RIOTBASE, "cpu/stm32/vectors") STM32_VENDOR_DIR = os.path.join(RIOTBASE, "cpu/stm32/include/vendor") STM32_CMSIS_FILE = os.path.join( RIOTBASE, STM32_VENDOR_DIR, "cmsis/{}/Include/{}.h") VECTORS_FORMAT = """ /* * PLEASE DON'T EDIT * * This file was automatically generated by * ./cpu/stm32/dist/irqs/gen_vectors.py */ #include "vectors_cortexm.h" /* define a local dummy handler as it needs to be in the same compilation unit * as the alias definition */ void dummy_handler(void) {{ dummy_handler_default(); }} /* {cpu_line} specific interrupt vectors */ {isr_lines} /* CPU specific interrupt vector table */ ISR_VECTOR(1) const isr_t vector_cpu[CPU_IRQ_NUMOF] = {{ {irq_lines} }}; """ def parse_cmsis(cpu_line): """Parse the CMSIS to get the list IRQs.""" cpu_fam = cpu_line[5:7] if cpu_line == "STM32F030x4": # STM32F030x4 is provided in the RIOT codebase in a different location cpu_line_cmsis = os.path.join( STM32_VENDOR_DIR, "{}.h".format(cpu_line.lower())) else: cpu_line_cmsis = STM32_CMSIS_FILE.format( cpu_fam.lower(), cpu_line.lower()) with open(cpu_line_cmsis, 'rb') as cmsis: cmsis_content = cmsis.readlines() irq_lines = [] use_line = False for line in cmsis_content: try: line = line.decode() except UnicodeDecodeError: # skip line that contains non unicode characters continue # start filling lines after interrupt Doxygen comment if line.startswith("typedef enum"): use_line = True # use a regexp to get the available IRQs match = re.match(r"[ ]+([a-zA-Z0-9_]+_IRQn)[ ]+= \d+,", line) # Skip lines that don't match if match is None: continue # Skip remapped USB interrupt # (set as alias for USBWakeUp_IRQn on stm32f3) if "USBWakeUp_RMP_IRQn" in line: continue # Stop at the end of the IRQn_Type enum definition if "IRQn_Type" in line: break # Only append IRQ line if it should be used and is not empty if use_line: irq_lines.append(match.group(1).strip()) isrs = [ { "irq": irq, "func": "exti" if "EXTI" in irq else irq.lower().rsplit("_", 1)[0] } for irq in irq_lines ] return {"isrs": isrs, "cpu_line": cpu_line} def generate_vectors(context): """Use vector template string to generate the vectors C file.""" isr_line_format = "WEAK_DEFAULT void isr_{func}(void);" irq_line_format = " [{irq:<35}] = isr_{func}," isr_lines = [] irq_lines = [] for isr in context["isrs"]: isr_line = isr_line_format.format(**isr) if isr_line not in isr_lines: isr_lines.append(isr_line) irq_lines.append(irq_line_format.format(**isr)) vectors_content = VECTORS_FORMAT.format( cpu_line=context["cpu_line"], isr_lines="\n".join(isr_lines), irq_lines="\n".join(irq_lines), ) dest_file = os.path.join( STM32_VECTORS_DIR, "{}.c".format(context["cpu_line"]) ) with open(dest_file, "w") as f_dest: f_dest.write(vectors_content) def main(args): """Main function.""" context = parse_cmsis(args.cpu_line) generate_vectors(context) PARSER = argparse.ArgumentParser() PARSER.add_argument("cpu_line", help="STM32 CPU line") if __name__ == "__main__": main(PARSER.parse_args())