2 # SPDX-License-Identifier: GPL-2.0
3 # gen-sysreg.awk: arm64 sysreg header generator
5 # Usage: awk -f gen-sysreg.awk sysregs.txt
7 # Log an error and terminate
9 print "Error at " NR ": " msg > "/dev/stderr"
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.
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
19 function change_block(this, prev, new) {
21 fatal("unexpected " this " (inside " block ")")
26 # Sanity check the number of records for a field makes sense. If not, produce
27 # an error and terminate.
28 function expect_fields(nf) {
30 fatal(NF " fields found where " nf " expected")
33 # Print a CPP macro definition, padded with spaces so that the macro bodies
35 function define(name, val) {
36 printf "%-48s%s\n", "#define " name, val
39 # Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field
40 function 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)
47 # Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb
48 function parse_bitdef(reg, field, bitdef, _bits)
50 if (bitdef ~ /^[0-9]+$/) {
53 } else if (split(bitdef, _bits, ":") == 2) {
57 fatal("invalid bit-range definition '" bitdef "'")
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 "'")
68 fatal(reg "." field " invalid bit-range '" bitdef "'")
70 fatal(reg "." field " has invalid range " high "-" low)
76 print "#ifndef __ASM_SYSREG_DEFS_H"
77 print "#define __ASM_SYSREG_DEFS_H"
79 print "/* Generated file - do not edit */"
86 print "#endif /* __ASM_SYSREG_DEFS_H */"
89 # skip blank lines and comment lines
94 change_block("SysregFields", "None", "SysregFields")
109 fatal("Unspecified bits in " reg)
111 change_block("EndSysregFields", "SysregFields", "None")
113 define(reg "_RES0", "(" res0 ")")
114 define(reg "_RES1", "(" res1 ")")
125 change_block("Sysreg", "None", "Sysreg")
138 define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2)
139 define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")")
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)
156 fatal("Unspecified bits in " reg)
158 change_block("EndSysreg", "Sysreg", "None")
161 define(reg "_RES0", "(" res0 ")")
163 define(reg "_RES1", "(" res1 ")")
164 if (res0 != null || res1 != null)
179 # Currently this is effectivey a comment, in future we may want to emit
180 # defines for the fields.
181 /^Fields/ && (block == "Sysreg") {
185 fatal("Some fields already defined for " reg)
187 print "/* For " reg " fields see " $2 " */"
198 /^Res0/ && (block == "Sysreg" || block == "SysregFields") {
200 parse_bitdef(reg, "RES0", $2)
201 field = "RES0_" msb "_" lsb
203 res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")"
208 /^Res1/ && (block == "Sysreg" || block == "SysregFields") {
210 parse_bitdef(reg, "RES1", $2)
211 field = "RES1_" msb "_" lsb
213 res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")"
218 /^Field/ && (block == "Sysreg" || block == "SysregFields") {
221 parse_bitdef(reg, field, $2)
223 define_field(reg, field, msb, lsb)
229 /^Raz/ && (block == "Sysreg" || block == "SysregFields") {
231 parse_bitdef(reg, field, $2)
237 change_block("Enum", "Sysreg", "Enum")
240 parse_bitdef(reg, field, $2)
242 define_field(reg, field, msb, lsb)
248 change_block("EndEnum", "Enum", "Sysreg")
256 /0b[01]+/ && block == "Enum" {
261 define(reg "_" field "_" name, "UL(" val ")")
265 # Any lines not handled by previous rules are unexpected
267 fatal("unhandled statement")