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(name, val) {
48	printf "%-56s%s\n", "#define " name, val
49}
50
51# Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field
52function define_field(reg, field, msb, lsb) {
53	define(reg "_" field, "GENMASK(" msb ", " lsb ")")
54	define(reg "_" field "_MASK", "GENMASK(" msb ", " lsb ")")
55	define(reg "_" field "_SHIFT", lsb)
56	define(reg "_" field "_WIDTH", msb - lsb + 1)
57}
58
59# Print a field _SIGNED definition for a field
60function define_field_sign(reg, field, sign) {
61	define(reg "_" field "_SIGNED", sign)
62}
63
64# Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb
65function parse_bitdef(reg, field, bitdef, _bits)
66{
67	if (bitdef ~ /^[0-9]+$/) {
68		msb = bitdef
69		lsb = bitdef
70	} else if (split(bitdef, _bits, ":") == 2) {
71		msb = _bits[1]
72		lsb = _bits[2]
73	} else {
74		fatal("invalid bit-range definition '" bitdef "'")
75	}
76
77
78	if (msb != next_bit)
79		fatal(reg "." field " starts at " msb " not " next_bit)
80	if (63 < msb || msb < 0)
81		fatal(reg "." field " invalid high bit in '" bitdef "'")
82	if (63 < lsb || lsb < 0)
83		fatal(reg "." field " invalid low bit in '" bitdef "'")
84	if (msb < lsb)
85		fatal(reg "." field " invalid bit-range '" bitdef "'")
86	if (low > high)
87		fatal(reg "." field " has invalid range " high "-" low)
88
89	next_bit = lsb - 1
90}
91
92BEGIN {
93	print "#ifndef __ASM_SYSREG_DEFS_H"
94	print "#define __ASM_SYSREG_DEFS_H"
95	print ""
96	print "/* Generated file - do not edit */"
97	print ""
98
99	__current_block_depth = 0
100	__current_block[__current_block_depth] = "Root"
101}
102
103END {
104	if (__current_block_depth != 0)
105		fatal("Missing terminator for " block_current() " block")
106
107	print "#endif /* __ASM_SYSREG_DEFS_H */"
108}
109
110# skip blank lines and comment lines
111/^$/ { next }
112/^[\t ]*#/ { next }
113
114/^SysregFields/ && block_current() == "Root" {
115	block_push("SysregFields")
116
117	expect_fields(2)
118
119	reg = $2
120
121	res0 = "UL(0)"
122	res1 = "UL(0)"
123	unkn = "UL(0)"
124
125	next_bit = 63
126
127	next
128}
129
130/^EndSysregFields/ && block_current() == "SysregFields" {
131	if (next_bit > 0)
132		fatal("Unspecified bits in " reg)
133
134	define(reg "_RES0", "(" res0 ")")
135	define(reg "_RES1", "(" res1 ")")
136	define(reg "_UNKN", "(" unkn ")")
137	print ""
138
139	reg = null
140	res0 = null
141	res1 = null
142	unkn = null
143
144	block_pop()
145	next
146}
147
148/^Sysreg/ && block_current() == "Root" {
149	block_push("Sysreg")
150
151	expect_fields(7)
152
153	reg = $2
154	op0 = $3
155	op1 = $4
156	crn = $5
157	crm = $6
158	op2 = $7
159
160	res0 = "UL(0)"
161	res1 = "UL(0)"
162	unkn = "UL(0)"
163
164	define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2)
165	define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")")
166
167	define("SYS_" reg "_Op0", op0)
168	define("SYS_" reg "_Op1", op1)
169	define("SYS_" reg "_CRn", crn)
170	define("SYS_" reg "_CRm", crm)
171	define("SYS_" reg "_Op2", op2)
172
173	print ""
174
175	next_bit = 63
176
177	next
178}
179
180/^EndSysreg/ && block_current() == "Sysreg" {
181	if (next_bit > 0)
182		fatal("Unspecified bits in " reg)
183
184	if (res0 != null)
185		define(reg "_RES0", "(" res0 ")")
186	if (res1 != null)
187		define(reg "_RES1", "(" res1 ")")
188	if (unkn != null)
189		define(reg "_UNKN", "(" unkn ")")
190	if (res0 != null || res1 != null || unkn != null)
191		print ""
192
193	reg = null
194	op0 = null
195	op1 = null
196	crn = null
197	crm = null
198	op2 = null
199	res0 = null
200	res1 = null
201	unkn = null
202
203	block_pop()
204	next
205}
206
207# Currently this is effectivey a comment, in future we may want to emit
208# defines for the fields.
209/^Fields/ && block_current() == "Sysreg" {
210	expect_fields(2)
211
212	if (next_bit != 63)
213		fatal("Some fields already defined for " reg)
214
215	print "/* For " reg " fields see " $2 " */"
216	print ""
217
218        next_bit = 0
219	res0 = null
220	res1 = null
221	unkn = null
222
223	next
224}
225
226
227/^Res0/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
228	expect_fields(2)
229	parse_bitdef(reg, "RES0", $2)
230	field = "RES0_" msb "_" lsb
231
232	res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")"
233
234	next
235}
236
237/^Res1/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
238	expect_fields(2)
239	parse_bitdef(reg, "RES1", $2)
240	field = "RES1_" msb "_" lsb
241
242	res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")"
243
244	next
245}
246
247/^Unkn/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
248	expect_fields(2)
249	parse_bitdef(reg, "UNKN", $2)
250	field = "UNKN_" msb "_" lsb
251
252	unkn = unkn " | GENMASK_ULL(" msb ", " lsb ")"
253
254	next
255}
256
257/^Field/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
258	expect_fields(3)
259	field = $3
260	parse_bitdef(reg, field, $2)
261
262	define_field(reg, field, msb, lsb)
263	print ""
264
265	next
266}
267
268/^Raz/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
269	expect_fields(2)
270	parse_bitdef(reg, field, $2)
271
272	next
273}
274
275/^SignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
276	block_push("Enum")
277
278	expect_fields(3)
279	field = $3
280	parse_bitdef(reg, field, $2)
281
282	define_field(reg, field, msb, lsb)
283	define_field_sign(reg, field, "true")
284
285	next
286}
287
288/^UnsignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
289	block_push("Enum")
290
291	expect_fields(3)
292	field = $3
293	parse_bitdef(reg, field, $2)
294
295	define_field(reg, field, msb, lsb)
296	define_field_sign(reg, field, "false")
297
298	next
299}
300
301/^Enum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
302	block_push("Enum")
303
304	expect_fields(3)
305	field = $3
306	parse_bitdef(reg, field, $2)
307
308	define_field(reg, field, msb, lsb)
309
310	next
311}
312
313/^EndEnum/ && block_current() == "Enum" {
314
315	field = null
316	msb = null
317	lsb = null
318	print ""
319
320	block_pop()
321	next
322}
323
324/0b[01]+/ && block_current() == "Enum" {
325	expect_fields(2)
326	val = $1
327	name = $2
328
329	define(reg "_" field "_" name, "UL(" val ")")
330	next
331}
332
333# Any lines not handled by previous rules are unexpected
334{
335	fatal("unhandled statement")
336}
337