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$1 == "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$1 == "EndSysregFields" && block_current() == "SysregFields" {
131	expect_fields(1)
132	if (next_bit > 0)
133		fatal("Unspecified bits in " reg)
134
135	define(reg "_RES0", "(" res0 ")")
136	define(reg "_RES1", "(" res1 ")")
137	define(reg "_UNKN", "(" unkn ")")
138	print ""
139
140	reg = null
141	res0 = null
142	res1 = null
143	unkn = null
144
145	block_pop()
146	next
147}
148
149$1 == "Sysreg" && block_current() == "Root" {
150	block_push("Sysreg")
151
152	expect_fields(7)
153
154	reg = $2
155	op0 = $3
156	op1 = $4
157	crn = $5
158	crm = $6
159	op2 = $7
160
161	res0 = "UL(0)"
162	res1 = "UL(0)"
163	unkn = "UL(0)"
164
165	define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2)
166	define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")")
167
168	define("SYS_" reg "_Op0", op0)
169	define("SYS_" reg "_Op1", op1)
170	define("SYS_" reg "_CRn", crn)
171	define("SYS_" reg "_CRm", crm)
172	define("SYS_" reg "_Op2", op2)
173
174	print ""
175
176	next_bit = 63
177
178	next
179}
180
181$1 == "EndSysreg" && block_current() == "Sysreg" {
182	expect_fields(1)
183	if (next_bit > 0)
184		fatal("Unspecified bits in " reg)
185
186	if (res0 != null)
187		define(reg "_RES0", "(" res0 ")")
188	if (res1 != null)
189		define(reg "_RES1", "(" res1 ")")
190	if (unkn != null)
191		define(reg "_UNKN", "(" unkn ")")
192	if (res0 != null || res1 != null || unkn != null)
193		print ""
194
195	reg = null
196	op0 = null
197	op1 = null
198	crn = null
199	crm = null
200	op2 = null
201	res0 = null
202	res1 = null
203	unkn = null
204
205	block_pop()
206	next
207}
208
209# Currently this is effectivey a comment, in future we may want to emit
210# defines for the fields.
211($1 == "Fields" || $1 == "Mapping") && block_current() == "Sysreg" {
212	expect_fields(2)
213
214	if (next_bit != 63)
215		fatal("Some fields already defined for " reg)
216
217	print "/* For " reg " fields see " $2 " */"
218	print ""
219
220        next_bit = 0
221	res0 = null
222	res1 = null
223	unkn = null
224
225	next
226}
227
228
229$1 == "Res0" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
230	expect_fields(2)
231	parse_bitdef(reg, "RES0", $2)
232	field = "RES0_" msb "_" lsb
233
234	res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")"
235
236	next
237}
238
239$1 == "Res1" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
240	expect_fields(2)
241	parse_bitdef(reg, "RES1", $2)
242	field = "RES1_" msb "_" lsb
243
244	res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")"
245
246	next
247}
248
249$1 == "Unkn" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
250	expect_fields(2)
251	parse_bitdef(reg, "UNKN", $2)
252	field = "UNKN_" msb "_" lsb
253
254	unkn = unkn " | GENMASK_ULL(" msb ", " lsb ")"
255
256	next
257}
258
259$1 == "Field" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
260	expect_fields(3)
261	field = $3
262	parse_bitdef(reg, field, $2)
263
264	define_field(reg, field, msb, lsb)
265	print ""
266
267	next
268}
269
270$1 == "Raz" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
271	expect_fields(2)
272	parse_bitdef(reg, field, $2)
273
274	next
275}
276
277$1 == "SignedEnum" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
278	block_push("Enum")
279
280	expect_fields(3)
281	field = $3
282	parse_bitdef(reg, field, $2)
283
284	define_field(reg, field, msb, lsb)
285	define_field_sign(reg, field, "true")
286
287	next
288}
289
290$1 == "UnsignedEnum" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
291	block_push("Enum")
292
293	expect_fields(3)
294	field = $3
295	parse_bitdef(reg, field, $2)
296
297	define_field(reg, field, msb, lsb)
298	define_field_sign(reg, field, "false")
299
300	next
301}
302
303$1 == "Enum" && (block_current() == "Sysreg" || block_current() == "SysregFields") {
304	block_push("Enum")
305
306	expect_fields(3)
307	field = $3
308	parse_bitdef(reg, field, $2)
309
310	define_field(reg, field, msb, lsb)
311
312	next
313}
314
315$1 == "EndEnum" && block_current() == "Enum" {
316	expect_fields(1)
317
318	field = null
319	msb = null
320	lsb = null
321	print ""
322
323	block_pop()
324	next
325}
326
327/0b[01]+/ && block_current() == "Enum" {
328	expect_fields(2)
329	val = $1
330	name = $2
331
332	define(reg "_" field "_" name, "UL(" val ")")
333	next
334}
335
336# Any lines not handled by previous rules are unexpected
337{
338	fatal("unhandled statement")
339}
340