2 # Copyright (C) 1994-1995 Andrew Cagney <cagney@highland.com.au>
3 # Copyright (C) 1996-2023 Free Software Foundation, Inc.
5 # This file is part of the GNU simulators.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """Helper to generate spreg.[ch] files."""
23 from pathlib
import Path
25 from typing
import NamedTuple
, TextIO
28 FILE
= Path(__file__
).resolve()
43 class Spreg(NamedTuple
):
44 """A single spreg entry."""
52 def load_table(source
: Path
) -> list[Spreg
]:
53 """Load the spreg table & return all entries in it."""
56 with source
.open("r", encoding
="utf-8") as fp
:
57 for i
, line
in enumerate(fp
):
58 line
= line
.split("#", 1)[0].strip()
60 # Skip blank & comment lines.
63 fields
= line
.split(":")
64 assert len(fields
) == 4, f
"{source}:{i}: bad line: {line}"
66 name
=fields
[0].lower(),
67 reg_nr
=int(fields
[1]),
68 is_readonly
=int(fields
[2]),
69 length
=int(fields
[3]),
73 return sorted(ret
, key
=lambda x
: x
[1])
76 def print_copyleft(fp
: TextIO
) -> None:
77 """Write out the standard copyright & license file block."""
80 /* DO NOT EDIT: GENERATED BY {FILE.name}.
82 Copyright (C) 1994-1995 Andrew Cagney <cagney@highland.com.au>
83 Copyright (C) 1996-2022 Free Software Foundation, Inc.
85 This file is part of the GNU simulators.
87 This program is free software; you can redistribute it and/or modify
88 it under the terms of the GNU General Public License as published by
89 the Free Software Foundation; either version 3 of the License, or
90 (at your option) any later version.
92 This program is distributed in the hope that it will be useful,
93 but WITHOUT ANY WARRANTY; without even the implied warranty of
94 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
95 GNU General Public License for more details.
97 You should have received a copy of the GNU General Public License
98 along with this program. If not, see <http://www.gnu.org/licenses/>. */
103 def gen_header(table
: list[Spreg
], output
: Path
) -> None:
104 """Write header to |output| from spreg |table|."""
105 with output
.open("w", encoding
="utf-8") as fp
:
112 typedef unsigned_word spreg;
119 fp
.write(f
" spr_{spreg.name} = {spreg.reg_nr},\n")
123 nr_of_sprs = {NR_OF_SPRS}
129 for attr
in SPREG_ATTRIBUTES
:
130 ret_type
= "const char *" if attr
== "name" else "int"
131 fp
.write(f
"INLINE_SPREG({ret_type}) spr_{attr}(sprs spr);\n")
135 #endif /* _SPREG_H_ */
140 def gen_switch_is_valid(table
: list[Spreg
], fp
: TextIO
) -> None:
141 """Generate switch table for is_valid property."""
142 fp
.write(" switch (spr) {\n")
143 # Output all the known registers. We'll return 1 for them.
145 fp
.write(f
" case {spreg.reg_nr}:\n")
146 # All other registers return 0.
156 def gen_switch_is_readonly(table
: list[Spreg
], fp
: TextIO
) -> None:
157 """Generate switch table for is_readonly property."""
158 # Find any readonly registers and output a switch for them.
159 # If there aren't any, we can optimize this away to a single return.
160 output_switch
= False
163 if spreg
.is_readonly
:
164 if not output_switch
:
165 fp
.write(" switch (spr) {\n")
168 fp
.write(f
" case {spreg.reg_nr}:\n")
170 fp
.write(" return 1;\n")
174 fp
.write(" return 0;\n")
177 def gen_switch_length(table
: list[Spreg
], fp
: TextIO
) -> None:
178 """Generate switch table for length property."""
179 # Find any registers with a length property and output a switch for them.
180 # If there aren't any, we can optimize this away to a single return.
181 output_switch
= False
184 if not output_switch
:
185 fp
.write(" switch (spr) {\n")
187 fp
.write(f
" case {spreg.reg_nr}:\n")
188 fp
.write(f
" return {spreg.length};\n")
192 fp
.write(" return 0;\n")
195 def gen_source(table
: list[Spreg
], output
: Path
) -> None:
196 """Write header to |output| from spreg |table|."""
197 with output
.open("w", encoding
="utf-8") as fp
:
207 typedef struct _spreg_info {
215 static const spreg_info spr_info[nr_of_sprs+1] = {
219 entries
= iter(table
)
220 entry
= next(entries
)
221 for spreg_nr
in range(0, NR_OF_SPRS
+ 1):
222 if entry
is None or spreg_nr
< entry
.reg_nr
:
223 fp
.write(f
" {{ 0, 0, 0, 0, {spreg_nr} }},\n")
226 f
' {{ "{entry.name}", 1, {entry.length}, {entry.is_readonly}, spr_{entry.name} /*{spreg_nr}*/ }},\n'
228 entry
= next(entries
, None)
231 for attr
in SPREG_ATTRIBUTES
:
232 ret_type
= "const char *" if attr
== "name" else "int"
235 INLINE_SPREG({ret_type}) spr_{attr}(sprs spr)
240 if attr
not in ("index", "name"):
243 #ifdef WITH_SPREG_SWITCH_TABLE
246 if attr
== "is_valid":
247 gen_switch_is_valid(table
, fp
)
248 elif attr
== "is_readonly":
249 gen_switch_is_readonly(table
, fp
)
250 elif attr
== "length":
251 gen_switch_length(table
, fp
)
253 assert False, f
"{attr}: Unknown attribute"
255 fp
.write(f
" return spr_info[spr].{attr};\n")
256 if attr
not in ("index", "name"):
260 fp
.write("\n#endif /* _SPREG_C_ */\n")
263 def get_parser() -> argparse
.ArgumentParser
:
264 """Get CLI parser."""
265 parser
= argparse
.ArgumentParser(
267 formatter_class
=argparse
.RawDescriptionHelpFormatter
,
272 default
=DIR
/ "ppc-spr-table",
273 help="path to source table",
275 parser
.add_argument("--header", type=Path
, help="path to header (.h) file")
276 parser
.add_argument("--source", type=Path
, help="path to source (.c) file")
280 def parse_args(argv
: list[str]) -> argparse
.Namespace
:
281 """Process the command line & default options."""
282 parser
= get_parser()
283 opts
= parser
.parse_args(argv
)
285 if not opts
.header
and not opts
.source
:
286 opts
.header
= DIR
/ "spreg.h"
287 opts
.source
= DIR
/ "spreg.c"
292 def main(argv
: list[str]) -> int:
293 """The main entry point for scripts."""
294 opts
= parse_args(argv
)
296 table
= load_table(opts
.table
)
298 gen_header(table
, opts
.header
)
300 gen_source(table
, opts
.source
)
304 if __name__
== "__main__":
305 sys
.exit(main(sys
.argv
[1:]))