1#!/usr/bin/env python3
2#
3# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
4#
5# SPDX-License-Identifier: BSD-3-Clause
6
7from Cheetah.Template import Template
8
9import argparse
10import itertools
11import subprocess
12import logging
13import sys
14
15logger = logging.getLogger(__name__)
16
17valid_access_strs = \
18    set([''.join(x) for x in itertools.chain.from_iterable(
19        itertools.combinations('oOrwRW', r) for r in range(1, 6))])
20
21
22class register:
23    def __init__(self, name, type_name, variants=[], access='rw'):
24        if access in ['o', 'O']:
25            access += 'rw'
26        if access not in valid_access_strs:
27            logger.error("Invalid access type '%s'", access)
28            sys.exit(1)
29        self.name = name
30        self.type_name = type_name
31        self._variants = variants
32        self._read = 'r' in access
33        self._write = 'w' in access
34        self._volatile_read = 'R' in access
35        self._barrier_write = 'W' in access
36        self._ordered = 'O' in access
37        self._non_ordered = 'o' in access or 'O' not in access
38
39    @property
40    def variants(self):
41        ret = []
42        type_name = self.type_name[:-1] if self.type_name.endswith(
43            '!') else self.type_name
44
45        for v in self._variants:
46            if v.endswith('!'):
47                ret.append((v[:-1],
48                            type_name if self.type_name.endswith(
49                                '!') else v[:-1]))
50            else:
51                ret.append(('_'.join((self.name, v)),
52                            type_name if self.type_name.endswith(
53                                '!') else '_'.join((type_name, v))))
54
55        if not ret:
56            ret = [(self.name, type_name)]
57        return sorted(ret)
58
59    @property
60    def is_readable(self):
61        return self._read
62
63    @property
64    def is_volatile(self):
65        return self._volatile_read
66
67    @property
68    def is_writable(self):
69        return self._write
70
71    @property
72    def is_writeable_barrier(self):
73        return self._barrier_write
74
75    @property
76    def need_ordered(self):
77        return self._ordered
78
79    @property
80    def need_non_ordered(self):
81        return self._non_ordered
82
83
84def generate_accessors(template, input, ns):
85    registers = {}
86
87    for line in input.splitlines():
88        if line.startswith('//'):
89            continue
90        tokens = line.split(maxsplit=1)
91        if not tokens:
92            continue
93        name = tokens[0]
94        if name in registers:
95            raise Exception("duplicate register:", name)
96
97        if len(tokens) == 1:
98            registers[name] = register(name, name)
99            continue
100        args = tokens[1]
101
102        type_name = name
103        if args.startswith('<'):
104            type_name, args = args[1:].split('>', maxsplit=1)
105            args = args.strip()
106
107        identifiers = []
108        if args.startswith('['):
109            identifiers, args = args[1:].split(']', maxsplit=1)
110            identifiers = identifiers.split()
111            args = args.strip()
112
113        if args:
114            registers[name] = register(name, type_name, identifiers, args)
115        else:
116            registers[name] = register(name, type_name, identifiers)
117
118    ns['registers'] = [registers[r] for r in sorted(registers.keys())]
119
120    output = str(Template(file=template, searchList=ns))
121
122    return output
123
124
125def main():
126    logging.basicConfig(
127        level=logging.INFO,
128        format="%(message)s",
129    )
130
131    args = argparse.ArgumentParser()
132
133    mode_args = args.add_mutually_exclusive_group(required=True)
134    mode_args.add_argument('-t', '--template',
135                           type=argparse.FileType('r', encoding="utf-8"),
136                           help="Template file used to generate output")
137
138    args.add_argument('-o', '--output',
139                      type=argparse.FileType('w', encoding="utf-8"),
140                      default=sys.stdout, help="Write output to file")
141    args.add_argument("-f", "--formatter",
142                      help="specify clang-format to format the code")
143    args.add_argument("input", metavar='INPUT', nargs='*',
144                      help="Input type register file to process",
145                      type=argparse.FileType('r', encoding="utf-8"))
146    options = args.parse_args()
147
148    output = ""
149
150    input = ""
151    for f in options.input:
152        input += f.read()
153        f.close()
154
155    output += generate_accessors(options.template, input, {})
156
157    if options.formatter:
158        ret = subprocess.run([options.formatter], input=output.encode("utf-8"),
159                             stdout=subprocess.PIPE)
160        output = ret.stdout.decode("utf-8")
161        if ret.returncode != 0:
162            raise Exception("failed to format output:\n ", ret.stderr)
163
164    options.output.write(output)
165
166
167if __name__ == '__main__':
168    main()
169