1#!/usr/bin/env python3 2# Copyright (c) 2022 Intel corporation 3# SPDX-License-Identifier: Apache-2.0 4import argparse 5import re 6 7# Scratch register allocator. Zephyr uses multiple Xtensa SRs as 8# scratch space for various special purposes. Unfortunately the 9# configurable architecture means that not all registers will be the 10# same on every device. This script parses a pre-cooked ("gcc -E 11# -dM") core-isa.h file for the current architecture and assigns 12# registers to usages. 13 14def parse_args(): 15 parser = argparse.ArgumentParser(allow_abbrev=False) 16 17 parser.add_argument("--coherence", action="store_true", 18 help="Enable scratch registers for CONFIG_KERNEL_COHERENCE") 19 parser.add_argument("--mmu", action="store_true", 20 help="Enable scratch registers for MMU usage") 21 parser.add_argument("--syscall-scratch", action="store_true", 22 help="Enable scratch registers for syscalls if needed") 23 parser.add_argument("coreisa", 24 help="Path to preprocessed core-isa.h") 25 parser.add_argument("outfile", 26 help="Output file") 27 28 return parser.parse_args() 29 30args = parse_args() 31 32NEEDED = ["A0SAVE", "CPU"] 33if args.mmu: 34 NEEDED += ["DBLEXC", "DEPC_SAVE", "EXCCAUSE_SAVE"] 35if args.coherence: 36 NEEDED += ["FLUSH"] 37 38coreisa = args.coreisa 39outfile = args.outfile 40 41syms = {} 42 43def get(s): 44 return syms[s] if s in syms else 0 45 46with open(coreisa) as infile: 47 for line in infile.readlines(): 48 m = re.match(r"^#define\s+([^ ]+)\s*(.*)", line.rstrip()) 49 if m: 50 syms[m.group(1)] = m.group(2) 51 52# Use MISC registers first if available, that's what they're for 53regs = [ f"MISC{n}" for n in range(0, int(get("XCHAL_NUM_MISC_REGS"))) ] 54 55if args.syscall_scratch: 56 # If there is no THREADPTR, we need to use syscall for 57 # arch_is_user_context() where the code needs a scratch 58 # register. 59 have_threadptr = int(get("XCHAL_HAVE_THREADPTR")) 60 if have_threadptr == 0: 61 NEEDED.append("SYSCALL_SCRATCH") 62 63# Next come EXCSAVE. Also record our highest non-debug interrupt level. 64maxint = 0 65for il in range(1, 1 + int(get("XCHAL_NUM_INTLEVELS"))): 66 regs.append(f"EXCSAVE{il}") 67 if il != int(get("XCHAL_DEBUGLEVEL")): 68 maxint = max(il, maxint) 69 70# Find the highest priority software interrupt. We'll use that for 71# arch_irq_offload(). 72irqoff_level = -1 73irqoff_int = -1 74for sym, val in syms.items(): 75 if val == "XTHAL_INTTYPE_SOFTWARE": 76 m = re.match(r"XCHAL_INT(\d+)_TYPE", sym) 77 if m: 78 intnum = int(m.group(1)) 79 levelsym = f"XCHAL_INT{intnum}_LEVEL" 80 if levelsym in syms: 81 intlevel = int(syms[levelsym]) 82 if intlevel > irqoff_level: 83 irqoff_int = intnum 84 irqoff_level = intlevel 85 86# Now emit our output header with the assignments we chose 87with open(outfile, "w") as f: 88 f.write("/* Generated File, see gen_zsr.py */\n") 89 f.write("#ifndef ZEPHYR_ZSR_H\n") 90 f.write("#define ZEPHYR_ZSR_H\n") 91 for i, need in enumerate(NEEDED): 92 f.write(f"# define ZSR_{need} {regs[i]}\n") 93 f.write(f"# define ZSR_{need}_STR \"{regs[i]}\"\n") 94 95 # Emit any remaining registers as generics 96 for i in range(len(NEEDED), len(regs)): 97 f.write(f"# define ZSR_EXTRA{i - len(NEEDED)} {regs[i]}\n") 98 f.write(f"# define ZSR_EXTRA{i - len(NEEDED)}_STR \"{regs[i]}\"\n") 99 100 # Also, our highest level EPC/EPS registers 101 f.write(f"# define ZSR_RFI_LEVEL {maxint}\n") 102 f.write(f"# define ZSR_EPC EPC{maxint}\n") 103 f.write(f"# define ZSR_EPS EPS{maxint}\n") 104 105 # And the irq offset interrupt 106 if irqoff_int >= 0: 107 f.write(f"# define ZSR_IRQ_OFFLOAD_INT {irqoff_int}\n") 108 109 f.write("#endif\n") 110