xref: /openbmc/linux/arch/arm64/tools/gen-sysreg.awk (revision 27e45f2e)
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
7# Log an error and terminate
8function fatal(msg) {
9	print "Error at " NR ": " msg > "/dev/stderr"
10	exit 1
11}
12
13# Sanity check that the start or end of a block makes sense at this point in
14# the file. If not, produce an error and terminate.
15#
16# @this - the $Block or $EndBlock
17# @prev - the only valid block to already be in (value of @block)
18# @new - the new value of @block
19function change_block(this, prev, new) {
20	if (block != prev)
21		fatal("unexpected " this " (inside " block ")")
22
23	block = new
24}
25
26# Sanity check the number of records for a field makes sense. If not, produce
27# an error and terminate.
28function expect_fields(nf) {
29	if (NF != nf)
30		fatal(NF " fields found where " nf " expected")
31}
32
33# Print a CPP macro definition, padded with spaces so that the macro bodies
34# line up in a column
35function define(name, val) {
36	printf "%-56s%s\n", "#define " name, val
37}
38
39# Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field
40function define_field(reg, field, msb, lsb) {
41	define(reg "_" field, "GENMASK(" msb ", " lsb ")")
42	define(reg "_" field "_MASK", "GENMASK(" msb ", " lsb ")")
43	define(reg "_" field "_SHIFT", lsb)
44	define(reg "_" field "_WIDTH", msb - lsb + 1)
45}
46
47# Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb
48function parse_bitdef(reg, field, bitdef, _bits)
49{
50	if (bitdef ~ /^[0-9]+$/) {
51		msb = bitdef
52		lsb = bitdef
53	} else if (split(bitdef, _bits, ":") == 2) {
54		msb = _bits[1]
55		lsb = _bits[2]
56	} else {
57		fatal("invalid bit-range definition '" bitdef "'")
58	}
59
60
61	if (msb != next_bit)
62		fatal(reg "." field " starts at " msb " not " next_bit)
63	if (63 < msb || msb < 0)
64		fatal(reg "." field " invalid high bit in '" bitdef "'")
65	if (63 < lsb || lsb < 0)
66		fatal(reg "." field " invalid low bit in '" bitdef "'")
67	if (msb < lsb)
68		fatal(reg "." field " invalid bit-range '" bitdef "'")
69	if (low > high)
70		fatal(reg "." field " has invalid range " high "-" low)
71
72	next_bit = lsb - 1
73}
74
75BEGIN {
76	print "#ifndef __ASM_SYSREG_DEFS_H"
77	print "#define __ASM_SYSREG_DEFS_H"
78	print ""
79	print "/* Generated file - do not edit */"
80	print ""
81
82	block = "None"
83}
84
85END {
86	print "#endif /* __ASM_SYSREG_DEFS_H */"
87}
88
89# skip blank lines and comment lines
90/^$/ { next }
91/^[\t ]*#/ { next }
92
93/^SysregFields/ {
94	change_block("SysregFields", "None", "SysregFields")
95	expect_fields(2)
96
97	reg = $2
98
99	res0 = "UL(0)"
100	res1 = "UL(0)"
101
102	next_bit = 63
103
104	next
105}
106
107/^EndSysregFields/ {
108	if (next_bit > 0)
109		fatal("Unspecified bits in " reg)
110
111	change_block("EndSysregFields", "SysregFields", "None")
112
113	define(reg "_RES0", "(" res0 ")")
114	define(reg "_RES1", "(" res1 ")")
115	print ""
116
117	reg = null
118	res0 = null
119	res1 = null
120
121	next
122}
123
124/^Sysreg/ {
125	change_block("Sysreg", "None", "Sysreg")
126	expect_fields(7)
127
128	reg = $2
129	op0 = $3
130	op1 = $4
131	crn = $5
132	crm = $6
133	op2 = $7
134
135	res0 = "UL(0)"
136	res1 = "UL(0)"
137
138	define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2)
139	define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")")
140
141	define("SYS_" reg "_Op0", op0)
142	define("SYS_" reg "_Op1", op1)
143	define("SYS_" reg "_CRn", crn)
144	define("SYS_" reg "_CRm", crm)
145	define("SYS_" reg "_Op2", op2)
146
147	print ""
148
149	next_bit = 63
150
151	next
152}
153
154/^EndSysreg/ {
155	if (next_bit > 0)
156		fatal("Unspecified bits in " reg)
157
158	change_block("EndSysreg", "Sysreg", "None")
159
160	if (res0 != null)
161		define(reg "_RES0", "(" res0 ")")
162	if (res1 != null)
163		define(reg "_RES1", "(" res1 ")")
164	if (res0 != null || res1 != null)
165		print ""
166
167	reg = null
168	op0 = null
169	op1 = null
170	crn = null
171	crm = null
172	op2 = null
173	res0 = null
174	res1 = null
175
176	next
177}
178
179# Currently this is effectivey a comment, in future we may want to emit
180# defines for the fields.
181/^Fields/ && (block == "Sysreg") {
182	expect_fields(2)
183
184	if (next_bit != 63)
185		fatal("Some fields already defined for " reg)
186
187	print "/* For " reg " fields see " $2 " */"
188	print ""
189
190        next_bit = 0
191	res0 = null
192	res1 = null
193
194	next
195}
196
197
198/^Res0/ && (block == "Sysreg" || block == "SysregFields") {
199	expect_fields(2)
200	parse_bitdef(reg, "RES0", $2)
201	field = "RES0_" msb "_" lsb
202
203	res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")"
204
205	next
206}
207
208/^Res1/ && (block == "Sysreg" || block == "SysregFields") {
209	expect_fields(2)
210	parse_bitdef(reg, "RES1", $2)
211	field = "RES1_" msb "_" lsb
212
213	res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")"
214
215	next
216}
217
218/^Field/ && (block == "Sysreg" || block == "SysregFields") {
219	expect_fields(3)
220	field = $3
221	parse_bitdef(reg, field, $2)
222
223	define_field(reg, field, msb, lsb)
224	print ""
225
226	next
227}
228
229/^Raz/ && (block == "Sysreg" || block == "SysregFields") {
230	expect_fields(2)
231	parse_bitdef(reg, field, $2)
232
233	next
234}
235
236/^Enum/ {
237	change_block("Enum", "Sysreg", "Enum")
238	expect_fields(3)
239	field = $3
240	parse_bitdef(reg, field, $2)
241
242	define_field(reg, field, msb, lsb)
243
244	next
245}
246
247/^EndEnum/ {
248	change_block("EndEnum", "Enum", "Sysreg")
249	field = null
250	msb = null
251	lsb = null
252	print ""
253	next
254}
255
256/0b[01]+/ && block == "Enum" {
257	expect_fields(2)
258	val = $1
259	name = $2
260
261	define(reg "_" field "_" name, "UL(" val ")")
262	next
263}
264
265# Any lines not handled by previous rules are unexpected
266{
267	fatal("unhandled statement")
268}
269