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