core: arm32: generate system register access code

Replaces the hand crafted system register code in <arm32.h> and
<arm32_macros.S> with generated code based on arm32_sysreg.txt which is
extracted from the ARM Architecture Reference Manual.

The remaining hand crafted code for cp15 accesses is not covered by the
ARM Architecture Reference Manual.

A script is added to generate both assembly macros and static inline
functions to access the system registers.

Reviewed-by: Jerome Forissier <jerome.forissier@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/scripts/arm32_sysreg.py b/scripts/arm32_sysreg.py
new file mode 100755
index 0000000..bd0c619
--- /dev/null
+++ b/scripts/arm32_sysreg.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2018, Linaro Limited
+#
+from __future__ import print_function
+
+import argparse
+import sys
+import re
+
+
+def eprint(*args, **kwargs):
+    print(*args, file=sys.stderr, **kwargs)
+
+
+def my_err(line_number, msg):
+    eprint('Error: line:' + repr(line_number) + ' ' + msg)
+    sys.exit(1)
+
+
+def gen_read64_macro(reg_name, opc1, crm, descr):
+    print('')
+    if len(descr):
+        print('\t# ' + descr)
+    print('\t.macro read_' + reg_name.lower() + ' reg0, reg1')
+    print('\tmrrc\tp15, ' + opc1 + ', \\reg0, \\reg1, ' + crm)
+    print('\t.endm')
+
+
+def gen_write64_macro(reg_name, opc1, crm, descr):
+    print('')
+    if len(descr):
+        print('\t# ' + descr)
+    print('\t.macro write_' + reg_name.lower() + ' reg0, reg1')
+    print('\tmcrr\tp15, ' + opc1 + ', \\reg0, \\reg1, ' + crm)
+    print('\t.endm')
+
+
+def gen_read32_macro(reg_name, crn, opc1, crm, opc2, descr):
+    print('')
+    if len(descr):
+        print('\t# ' + descr)
+    print('\t.macro read_' + reg_name.lower() + ' reg')
+    print('\tmrc p15, ' + opc1 + ', \\reg, ' + crn + ', ' + crm + ', ' + opc2)
+    print('\t.endm')
+
+
+def gen_write32_macro(reg_name, crn, opc1, crm, opc2, descr):
+    print('')
+    if len(descr):
+        print('\t# ' + descr)
+    print('\t.macro write_' + reg_name.lower() + ' reg')
+    print('\tmcr p15, ' + opc1 + ', \\reg, ' + crn + ', ' + crm + ', ' + opc2)
+    print('\t.endm')
+
+
+def gen_write32_dummy_macro(reg_name, crn, opc1, crm, opc2, descr):
+    print('')
+    if len(descr):
+        print('\t# ' + descr)
+    print('\t.macro write_' + reg_name.lower())
+    print('\t# Register ignored')
+    print('\tmcr p15, ' + opc1 + ', r0, ' + crn + ', ' + crm + ', ' + opc2)
+    print('\t.endm')
+
+
+def gen_read64_func(reg_name, opc1, crm, descr):
+    print('')
+    if len(descr):
+        print('/* ' + descr + ' */')
+    print('static inline uint64_t read_' + reg_name.lower() + '(void)')
+    print('{')
+    print('\tuint64_t v;')
+    print('')
+    print('\tasm volatile ("mrrc p15, ' + opc1 + ', %Q0, %R0, ' +
+          crm + '"' + ' : "=r"  (v));')
+    print('')
+    print('\treturn v;')
+    print('}')
+
+
+def gen_write64_func(reg_name, opc1, crm, descr):
+    print('')
+    if len(descr):
+        print('/* ' + descr + ' */')
+    print('static inline void write_' + reg_name.lower() + '(uint64_t v)')
+    print('{')
+    print('\tasm volatile ("mcrr p15, ' + opc1 + ', %Q0, %R0, ' +
+          crm + '"' + ' : : "r"  (v));')
+    print('}')
+
+
+def gen_read32_func(reg_name, crn, opc1, crm, opc2, descr):
+    print('')
+    if len(descr):
+        print('/* ' + descr + ' */')
+    print('static inline uint32_t read_' + reg_name.lower() + '(void)')
+    print('{')
+    print('\tuint32_t v;')
+    print('')
+    print('\tasm volatile ("mrc p15, ' + opc1 + ', %0, ' + crn + ', ' +
+          crm + ', ' + opc2 + '"' + ' : "=r"  (v));')
+    print('')
+    print('\treturn v;')
+    print('}')
+
+
+def gen_write32_func(reg_name, crn, opc1, crm, opc2, descr):
+    print('')
+    if len(descr):
+        print('/* ' + descr + ' */')
+    print('static inline void write_' + reg_name.lower() + '(uint32_t v)')
+    print('{')
+    print('\tasm volatile ("mcr p15, ' + opc1 + ', %0, ' + crn + ', ' +
+          crm + ', ' + opc2 + '"' + ' : : "r"  (v));')
+    print('}')
+
+
+def gen_write32_dummy_func(reg_name, crn, opc1, crm, opc2, descr):
+    print('')
+    if len(descr):
+        print('/* ' + descr + ' */')
+    print('static inline void write_' + reg_name.lower() + '(void)')
+    print('{')
+    print('\t/* Register ignored */')
+    print('\tasm volatile ("mcr p15, ' + opc1 + ', r0, ' + crn + ', ' +
+          crm + ', ' + opc2 + '");')
+    print('}')
+
+
+def gen_file(line, line_number, s_file):
+    words = line.split()
+    if len(words) == 0:
+        return
+
+    if len(re.findall('^ *#', line)):
+        return
+
+    if len(re.findall('^ *@', line)):
+        comment = re.sub('^ *@', '', line)
+        comment = re.sub('^ *', '', comment)
+        comment = re.sub('[ \n]*$', '', comment)
+        if len(comment) == 0:
+            print('')
+            return
+        if s_file:
+            print('# ' + comment)
+        else:
+            print('/* ' + comment + ' */')
+        return
+
+    reg_name = words[0]
+    crn = words[1]
+    opc1 = words[2]
+    crm = words[3]
+    opc2 = words[4]
+    access_type = words[5]
+    descr = " ".join(words[6:])
+
+    read_access = access_type == 'RO' or access_type == 'RW'
+    write_access = (access_type == 'WO' or access_type == 'RW' or
+                    access_type == 'WOD')
+    dummy_access = access_type == 'WOD'
+
+    if not read_access and not write_access:
+        my_err(line_number, 'bad Access Type "' + access_type + '"')
+
+    if crn == '-':
+        if opc2 != '-':
+            my_err(line_number, 'bad opc2, expected -')
+
+        if read_access:
+            if s_file:
+                gen_read64_macro(reg_name, opc1, crm, descr)
+            else:
+                gen_read64_func(reg_name, opc1, crm, descr)
+
+        if s_file:
+            gen_write64_macro(reg_name, opc1, crm, descr)
+        else:
+            gen_write64_func(reg_name, opc1, crm, descr)
+    else:
+        if read_access:
+            if s_file:
+                gen_read32_macro(reg_name, crn, opc1, crm, opc2, descr)
+            else:
+                gen_read32_func(reg_name, crn, opc1, crm, opc2, descr)
+
+        if write_access:
+            if dummy_access:
+                if s_file:
+                    gen_write32_dummy_macro(reg_name, crn, opc1, crm, opc2,
+                                            descr)
+                else:
+                    gen_write32_dummy_func(reg_name, crn, opc1, crm, opc2,
+                                           descr)
+            else:
+                if s_file:
+                    gen_write32_macro(reg_name, crn, opc1, crm, opc2, descr)
+                else:
+                    gen_write32_func(reg_name, crn, opc1, crm, opc2, descr)
+
+
+def get_args():
+    parser = argparse.ArgumentParser(description='Generates instructions to '
+                                     'access ARM32 system registers.')
+
+    parser.add_argument('--s_file', action='store_true',
+                        help='Generate an Assembly instead of a C file')
+    parser.add_argument('--guard',
+                        help='Provide #ifdef <guard_argument> in C file')
+
+    return parser.parse_args()
+
+
+def main():
+    args = get_args()
+
+    cmnt = 'Automatically generated, do not edit'
+    if args.s_file:
+        print('# ' + cmnt)
+    else:
+        print('/* ' + cmnt + ' */')
+        if args.guard is not None:
+            print('#ifndef ' + args.guard.upper().replace('.', '_'))
+            print('#define ' + args.guard.upper().replace('.', '_'))
+
+    line_number = 0
+    for line in sys.stdin:
+        line_number = line_number + 1
+        gen_file(line, line_number, args.s_file)
+
+    if not args.s_file and args.guard is not None:
+        print('#endif /*' + args.guard.upper().replace('.', '_') + '*/')
+
+
+if __name__ == '__main__':
+    main()