xref: /linux/arch/arm64/tools/gen-sysreg.awk (revision 7fc2cd2e4b398c57c9cf961cfea05eadbf34c05c)
1#!/bin/awk -f
2# SPDX-License-Identifier: GPL-2.0
3# gen-sysreg.awk: arm64 sysreg header generator
4#
5# Usage: awk -f gen-sysreg.awk sysregs.txt
6
7function block_current() {
8	return __current_block[__current_block_depth];
9}
10
11# Log an error and terminate
12function fatal(msg) {
13	print "Error at " NR ": " msg > "/dev/stderr"
14
15	printf "Current block nesting:"
16
17	for (i = 0; i <= __current_block_depth; i++) {
18		printf " " __current_block[i]
19	}
20	printf "\n"
21
22	exit 1
23}
24
25# Enter a new block, setting the active block to @block
26function block_push(block) {
27	__current_block[++__current_block_depth] = block
28}
29
30# Exit a block, setting the active block to the parent block
31function block_pop() {
32	if (__current_block_depth == 0)
33		fatal("error: block_pop() in root block")
34
35	__current_block_depth--;
36}
37
38# Sanity check the number of records for a field makes sense. If not, produce
39# an error and terminate.
40function expect_fields(nf) {
41	if (NF != nf)
42		fatal(NF " fields found where " nf " expected")
43}
44
45# Print a CPP macro definition, padded with spaces so that the macro bodies
46# line up in a column
47function define(prefix, name, val) {
48	printf "%-56s%s\n", "#define " prefix name, val
49}
50
51# Same as above, but without a prefix
52function define_reg(name, val) {
53	define(null, name, val)
54}
55
56# Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field
57function define_field(prefix, reg, field, msb, lsb) {
58	define(prefix, reg "_" field, "GENMASK(" msb ", " lsb ")")
59	define(prefix, reg "_" field "_MASK", "GENMASK(" msb ", " lsb ")")
60	define(prefix, reg "_" field "_SHIFT", lsb)
61	define(prefix, reg "_" field "_WIDTH", msb - lsb + 1)
62}
63
64# Print a field _SIGNED definition for a field
65function define_field_sign(prefix, reg, field, sign) {
66	define(prefix, reg "_" field "_SIGNED", sign)
67}
68
69# Print the Res0, Res1, Unkn masks
70function define_resx_unkn(prefix, reg, res0, res1, unkn) {
71	if (res0 != null)
72		define(prefix, reg "_RES0", "(" res0 ")")
73	if (res1 != null)
74		define(prefix, reg "_RES1", "(" res1 ")")
75	if (unkn != null)
76		define(prefix, reg "_UNKN", "(" unkn ")")
77	if (res0 != null || res1 != null || unkn != null)
78		print ""
79}
80
81# Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb
82function parse_bitdef(reg, field, bitdef, _bits)
83{
84	if (bitdef ~ /^[0-9]+$/) {
85		msb = bitdef
86		lsb = bitdef
87	} else if (split(bitdef, _bits, ":") == 2) {
88		msb = _bits[1]
89		lsb = _bits[2]
90	} else {
91		fatal("invalid bit-range definition '" bitdef "'")
92	}
93
94
95	if (msb != next_bit)
96		fatal(reg "." field " starts at " msb " not " next_bit)
97	if (63 < msb || msb < 0)
98		fatal(reg "." field " invalid high bit in '" bitdef "'")
99	if (63 < lsb || lsb < 0)
100		fatal(reg "." field " invalid low bit in '" bitdef "'")
101	if (msb < lsb)
102		fatal(reg "." field " invalid bit-range '" bitdef "'")
103	if (low > high)
104		fatal(reg "." field " has invalid range " high "-" low)
105
106	next_bit = lsb - 1
107}
108
109BEGIN {
110	print "#ifndef __ASM_SYSREG_DEFS_H"
111	print "#define __ASM_SYSREG_DEFS_H"
112	print ""
113	print "/* Generated file - do not edit */"
114	print ""
115
116	__current_block_depth = 0
117	__current_block[__current_block_depth] = "Root"
118}
119
120END {
121	if (__current_block_depth != 0)
122		fatal("Missing terminator for " block_current() " block")
123
124	print "#endif /* __ASM_SYSREG_DEFS_H */"
125}
126
127# skip blank lines and comment lines
128/^$/ { next }
129/^[\t ]*#/ { next }
130
131$1 == "SysregFields" && block_current() == "Root" {
132	block_push("SysregFields")
133
134	expect_fields(2)
135
136	reg = $2
137
138	res0 = "UL(0)"
139	res1 = "UL(0)"
140	unkn = "UL(0)"
141
142	if (reg in defined_fields)
143		fatal("Duplicate SysregFields definition for " reg)
144	defined_fields[reg] = 1
145
146	next_bit = 63
147
148	delete seen_prefixes
149
150	next
151}
152
153$1 == "EndSysregFields" && block_current() == "SysregFields" {
154	expect_fields(1)
155	if (next_bit >= 0)
156		fatal("Unspecified bits in " reg)
157
158	define_resx_unkn(prefix, reg, res0, res1, unkn)
159
160	reg = null
161	res0 = null
162	res1 = null
163	unkn = null
164
165	block_pop()
166	next
167}
168
169$1 == "Sysreg" && block_current() == "Root" {
170	block_push("Sysreg")
171
172	expect_fields(7)
173
174	reg = $2
175	op0 = $3
176	op1 = $4
177	crn = $5
178	crm = $6
179	op2 = $7
180
181	res0 = "UL(0)"
182	res1 = "UL(0)"
183	unkn = "UL(0)"
184
185	if (reg in defined_regs)
186		fatal("Duplicate Sysreg definition for " reg)
187	defined_regs[reg] = 1
188
189	define_reg("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2)
190	define_reg("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")")
191
192	define_reg("SYS_" reg "_Op0", op0)
193	define_reg("SYS_" reg "_Op1", op1)
194	define_reg("SYS_" reg "_CRn", crn)
195	define_reg("SYS_" reg "_CRm", crm)
196	define_reg("SYS_" reg "_Op2", op2)
197
198	print ""
199
200	prefix = null
201	next_bit = 63
202
203	delete seen_prefixes
204
205	next
206}
207
208$1 == "EndSysreg" && block_current() == "Sysreg" {
209	expect_fields(1)
210	if (next_bit >= 0)
211		fatal("Unspecified bits in " reg)
212
213	define_resx_unkn(prefix, reg, res0, res1, unkn)
214
215	reg = null
216	op0 = null
217	op1 = null
218	crn = null
219	crm = null
220	op2 = null
221	res0 = null
222	res1 = null
223	unkn = null
224	prefix = null
225
226	block_pop()
227	next
228}
229
230# Currently this is effectivey a comment, in future we may want to emit
231# defines for the fields.
232($1 == "Fields" || $1 == "Mapping") && block_current() == "Sysreg" {
233	expect_fields(2)
234
235	if (next_bit != 63)
236		fatal("Some fields already defined for " reg)
237
238	print "/* For " reg " fields see " $2 " */"
239	print ""
240
241	next_bit = -1
242	res0 = null
243	res1 = null
244	unkn = null
245
246	next
247}
248
249$1 == "Res0" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
250	expect_fields(2)
251	parse_bitdef(reg, "RES0", $2)
252	field = "RES0_" msb "_" lsb
253
254	res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")"
255
256	next
257}
258
259$1 == "Res1" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
260	expect_fields(2)
261	parse_bitdef(reg, "RES1", $2)
262	field = "RES1_" msb "_" lsb
263
264	res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")"
265
266	next
267}
268
269$1 == "Unkn" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
270	expect_fields(2)
271	parse_bitdef(reg, "UNKN", $2)
272	field = "UNKN_" msb "_" lsb
273
274	unkn = unkn " | GENMASK_ULL(" msb ", " lsb ")"
275
276	next
277}
278
279$1 == "Field" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
280	expect_fields(3)
281	field = $3
282	parse_bitdef(reg, field, $2)
283
284	define_field(prefix, reg, field, msb, lsb)
285	print ""
286
287	next
288}
289
290$1 == "Raz" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
291	expect_fields(2)
292	parse_bitdef(reg, field, $2)
293
294	next
295}
296
297$1 == "SignedEnum" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
298	block_push("Enum")
299
300	expect_fields(3)
301	field = $3
302	parse_bitdef(reg, field, $2)
303
304	define_field(prefix, reg, field, msb, lsb)
305	define_field_sign(prefix, reg, field, "true")
306
307	delete seen_enum_vals
308
309	next
310}
311
312$1 == "UnsignedEnum" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
313	block_push("Enum")
314
315	expect_fields(3)
316	field = $3
317	parse_bitdef(reg, field, $2)
318
319	define_field(prefix, reg, field, msb, lsb)
320	define_field_sign(prefix, reg, field, "false")
321
322	delete seen_enum_vals
323
324	next
325}
326
327$1 == "Enum" && (block_current() == "Sysreg" || block_current() == "SysregFields" || block_current() == "Prefix") {
328	block_push("Enum")
329
330	expect_fields(3)
331	field = $3
332	parse_bitdef(reg, field, $2)
333
334	define_field(prefix, reg, field, msb, lsb)
335
336	delete seen_enum_vals
337
338	next
339}
340
341$1 == "EndEnum" && block_current() == "Enum" {
342	expect_fields(1)
343
344	field = null
345	msb = null
346	lsb = null
347	print ""
348
349	delete seen_enum_vals
350
351	block_pop()
352	next
353}
354
355/0b[01]+/ && block_current() == "Enum" {
356	expect_fields(2)
357	val = $1
358	name = $2
359
360	if (val in seen_enum_vals)
361		fatal("Duplicate Enum value " val " for " name)
362	seen_enum_vals[val] = 1
363
364	define(prefix, reg "_" field "_" name, "UL(" val ")")
365	next
366}
367
368$1 == "Prefix" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
369	block_push("Prefix")
370
371	expect_fields(2)
372
373	if (next_bit < 63)
374		fatal("Prefixed fields must precede non-prefixed fields (" reg ")")
375
376	prefix = $2 "_"
377
378	if (prefix in seen_prefixes)
379		fatal("Duplicate prefix " prefix " for " reg)
380	seen_prefixes[prefix] = 1
381
382	res0 = "UL(0)"
383	res1 = "UL(0)"
384	unkn = "UL(0)"
385	next_bit = 63
386
387	next
388}
389
390$1 == "EndPrefix" && block_current() == "Prefix" {
391	expect_fields(1)
392	if (next_bit >= 0)
393		fatal("Unspecified bits in prefix " prefix " for " reg)
394
395	define_resx_unkn(prefix, reg, res0, res1, unkn)
396
397	prefix = null
398	res0 = "UL(0)"
399	res1 = "UL(0)"
400	unkn = "UL(0)"
401	next_bit = 63
402
403	block_pop()
404
405	next
406}
407
408# Any lines not handled by previous rules are unexpected
409{
410	fatal("unhandled statement")
411}
412