1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2018, Linaro Limited
5#
6
7
8import argparse
9import sys
10import re
11
12
13def eprint(*args, **kwargs):
14    print(*args, file=sys.stderr, **kwargs)
15
16
17def my_err(line_number, msg):
18    eprint('Error: line:' + repr(line_number) + ' ' + msg)
19    sys.exit(1)
20
21
22def gen_read64_macro(reg_name, opc1, crm, descr):
23    print('')
24    if len(descr):
25        print('\t# ' + descr)
26    print('\t.macro read_' + reg_name.lower() + ' reg0, reg1')
27    print('\tmrrc\tp15, ' + opc1 + ', \\reg0, \\reg1, ' + crm)
28    print('\t.endm')
29
30
31def gen_write64_macro(reg_name, opc1, crm, descr):
32    print('')
33    if len(descr):
34        print('\t# ' + descr)
35    print('\t.macro write_' + reg_name.lower() + ' reg0, reg1')
36    print('\tmcrr\tp15, ' + opc1 + ', \\reg0, \\reg1, ' + crm)
37    print('\t.endm')
38
39
40def gen_read32_macro(reg_name, crn, opc1, crm, opc2, descr):
41    print('')
42    if len(descr):
43        print('\t# ' + descr)
44    print('\t.macro read_' + reg_name.lower() + ' reg')
45    print('\tmrc p15, ' + opc1 + ', \\reg, ' + crn + ', ' + crm + ', ' + opc2)
46    print('\t.endm')
47
48
49def gen_write32_macro(reg_name, crn, opc1, crm, opc2, descr):
50    print('')
51    if len(descr):
52        print('\t# ' + descr)
53    print('\t.macro write_' + reg_name.lower() + ' reg')
54    print('\tmcr p15, ' + opc1 + ', \\reg, ' + crn + ', ' + crm + ', ' + opc2)
55    print('\t.endm')
56
57
58def gen_write32_dummy_macro(reg_name, crn, opc1, crm, opc2, descr):
59    print('')
60    if len(descr):
61        print('\t# ' + descr)
62    print('\t.macro write_' + reg_name.lower())
63    print('\t# Register ignored')
64    print('\tmcr p15, ' + opc1 + ', r0, ' + crn + ', ' + crm + ', ' + opc2)
65    print('\t.endm')
66
67
68def gen_read64_func(reg_name, opc1, crm, descr):
69    print('')
70    if len(descr):
71        print('/* ' + descr + ' */')
72    print('static inline __noprof uint64_t read_' + reg_name.lower() +
73          '(void)')
74    print('{')
75    print('\tuint64_t v;')
76    print('')
77    print('\tasm volatile ("mrrc p15, ' + opc1 + ', %Q0, %R0, ' +
78          crm + '"' + ' : "=r"  (v));')
79    print('')
80    print('\treturn v;')
81    print('}')
82
83
84def gen_write64_func(reg_name, opc1, crm, descr):
85    print('')
86    if len(descr):
87        print('/* ' + descr + ' */')
88    print('static inline __noprof void write_' + reg_name.lower() +
89          '(uint64_t v)')
90    print('{')
91    print('\tasm volatile ("mcrr p15, ' + opc1 + ', %Q0, %R0, ' +
92          crm + '"' + ' : : "r"  (v));')
93    print('}')
94
95
96def gen_read32_func(reg_name, crn, opc1, crm, opc2, descr):
97    print('')
98    if len(descr):
99        print('/* ' + descr + ' */')
100    print('static inline __noprof uint32_t read_' + reg_name.lower() +
101          '(void)')
102    print('{')
103    print('\tuint32_t v;')
104    print('')
105    print('\tasm volatile ("mrc p15, ' + opc1 + ', %0, ' + crn + ', ' +
106          crm + ', ' + opc2 + '"' + ' : "=r"  (v));')
107    print('')
108    print('\treturn v;')
109    print('}')
110
111
112def gen_write32_func(reg_name, crn, opc1, crm, opc2, descr):
113    print('')
114    if len(descr):
115        print('/* ' + descr + ' */')
116    print('static inline __noprof void write_' + reg_name.lower() +
117          '(uint32_t v)')
118    print('{')
119    print('\tasm volatile ("mcr p15, ' + opc1 + ', %0, ' + crn + ', ' +
120          crm + ', ' + opc2 + '"' + ' : : "r"  (v));')
121    print('}')
122
123
124def gen_write32_dummy_func(reg_name, crn, opc1, crm, opc2, descr):
125    print('')
126    if len(descr):
127        print('/* ' + descr + ' */')
128    print('static inline __noprof void write_' + reg_name.lower() + '(void)')
129    print('{')
130    print('\t/* Register ignored */')
131    print('\tasm volatile ("mcr p15, ' + opc1 + ', r0, ' + crn + ', ' +
132          crm + ', ' + opc2 + '");')
133    print('}')
134
135
136def gen_file(line, line_number, s_file):
137    words = line.split()
138    if len(words) == 0:
139        return
140
141    if len(re.findall('^ *#', line)):
142        return
143
144    if len(re.findall('^ *@', line)):
145        comment = re.sub('^ *@', '', line)
146        comment = re.sub('^ *', '', comment)
147        comment = re.sub('[ \n]*$', '', comment)
148        if len(comment) == 0:
149            print('')
150            return
151        if s_file:
152            print('# ' + comment)
153        else:
154            print('/* ' + comment + ' */')
155        return
156
157    reg_name = words[0]
158    crn = words[1]
159    opc1 = words[2]
160    crm = words[3]
161    opc2 = words[4]
162    access_type = words[5]
163    descr = " ".join(words[6:])
164
165    read_access = access_type == 'RO' or access_type == 'RW'
166    write_access = (access_type == 'WO' or access_type == 'RW' or
167                    access_type == 'WOD')
168    dummy_access = access_type == 'WOD'
169
170    if not read_access and not write_access:
171        my_err(line_number, 'bad Access Type "' + access_type + '"')
172
173    if crn == '-':
174        if opc2 != '-':
175            my_err(line_number, 'bad opc2, expected -')
176
177        if read_access:
178            if s_file:
179                gen_read64_macro(reg_name, opc1, crm, descr)
180            else:
181                gen_read64_func(reg_name, opc1, crm, descr)
182
183        if s_file:
184            gen_write64_macro(reg_name, opc1, crm, descr)
185        else:
186            gen_write64_func(reg_name, opc1, crm, descr)
187    else:
188        if read_access:
189            if s_file:
190                gen_read32_macro(reg_name, crn, opc1, crm, opc2, descr)
191            else:
192                gen_read32_func(reg_name, crn, opc1, crm, opc2, descr)
193
194        if write_access:
195            if dummy_access:
196                if s_file:
197                    gen_write32_dummy_macro(reg_name, crn, opc1, crm, opc2,
198                                            descr)
199                else:
200                    gen_write32_dummy_func(reg_name, crn, opc1, crm, opc2,
201                                           descr)
202            else:
203                if s_file:
204                    gen_write32_macro(reg_name, crn, opc1, crm, opc2, descr)
205                else:
206                    gen_write32_func(reg_name, crn, opc1, crm, opc2, descr)
207
208
209def get_args():
210    parser = argparse.ArgumentParser(description='Generates instructions to '
211                                     'access ARM32 system registers.')
212
213    parser.add_argument('--s_file', action='store_true',
214                        help='Generate an Assembly instead of a C file')
215    parser.add_argument('--guard',
216                        help='Provide #ifdef <guard_argument> in C file')
217
218    return parser.parse_args()
219
220
221def main():
222    args = get_args()
223
224    cmnt = 'Automatically generated, do not edit'
225    if args.s_file:
226        print('# ' + cmnt)
227    else:
228        print('/* ' + cmnt + ' */')
229        if args.guard is not None:
230            print('#ifndef ' + args.guard.upper().replace('.', '_'))
231            print('#define ' + args.guard.upper().replace('.', '_'))
232        print('#include <compiler.h>')
233
234    line_number = 0
235    for line in sys.stdin:
236        line_number = line_number + 1
237        gen_file(line, line_number, args.s_file)
238
239    if not args.s_file and args.guard is not None:
240        print('#endif /*' + args.guard.upper().replace('.', '_') + '*/')
241
242
243if __name__ == '__main__':
244    main()
245