Commit 013ecd44 authored by Mark Rutland's avatar Mark Rutland Committed by Will Deacon

arm64/sysreg: allow *Enum blocks in SysregFields blocks

We'd like to support Enum/SignedEnum/UnsignedEnum blocks within
SysregFields blocks, so that we can define enumerations for sets of
registers. This isn't currently supported by gen-sysreg.awk due to the
way we track the active block, which can't handle more than a single
layer of nesting, which imposes an awkward requirement that when ending
a block we know what the parent block is when calling change_block()

Make this nicer by using a stack of active blocks, with block_push() to
start a block, and block_pop() to end a block. Doing so means that we
only need to check the active block at the start of parsing a line: for
the start of a block we can check the parent is valid, and for the end
of a block we check that the active block is valid.

This structure makes the block parsing simpler and makes it easy to
permit a block to live under several potential parents (e.g. by
permitting Enum to start when the active block is Sysreg or
SysregFields). It also permits further nesting, if we need that in
future.

To aid debugging, the stack of active blocks is reported for fatal
errors, and an error is raised if the file is terminated without ending
the active block. For clarity I've renamed the top-level element from
"None" to "Root".

The Fields element it intended only for use within Sysreg blocks, and
does not make sense within SysregFields blocks, and so remains forbidden
within a SysregFields block.

I've verified using sha1sum that this patch does not change the
current generated contents of <asm/sysreg-defs.h>.
Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: default avatarAnshuman Khandual <anshuman.khandual@arm.com>
Reviewed-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20230306114836.2575432-1-mark.rutland@arm.comSigned-off-by: default avatarWill Deacon <will@kernel.org>
parent e8d018dd
...@@ -4,23 +4,35 @@ ...@@ -4,23 +4,35 @@
# #
# Usage: awk -f gen-sysreg.awk sysregs.txt # Usage: awk -f gen-sysreg.awk sysregs.txt
function block_current() {
return __current_block[__current_block_depth];
}
# Log an error and terminate # Log an error and terminate
function fatal(msg) { function fatal(msg) {
print "Error at " NR ": " msg > "/dev/stderr" print "Error at " NR ": " msg > "/dev/stderr"
printf "Current block nesting:"
for (i = 0; i <= __current_block_depth; i++) {
printf " " __current_block[i]
}
printf "\n"
exit 1 exit 1
} }
# Sanity check that the start or end of a block makes sense at this point in # Enter a new block, setting the active block to @block
# the file. If not, produce an error and terminate. function block_push(block) {
# __current_block[++__current_block_depth] = block
# @this - the $Block or $EndBlock }
# @prev - the only valid block to already be in (value of @block)
# @new - the new value of @block # Exit a block, setting the active block to the parent block
function change_block(this, prev, new) { function block_pop() {
if (block != prev) if (__current_block_depth == 0)
fatal("unexpected " this " (inside " block ")") fatal("error: block_pop() in root block")
block = new __current_block_depth--;
} }
# Sanity check the number of records for a field makes sense. If not, produce # Sanity check the number of records for a field makes sense. If not, produce
...@@ -84,10 +96,14 @@ BEGIN { ...@@ -84,10 +96,14 @@ BEGIN {
print "/* Generated file - do not edit */" print "/* Generated file - do not edit */"
print "" print ""
block = "None" __current_block_depth = 0
__current_block[__current_block_depth] = "Root"
} }
END { END {
if (__current_block_depth != 0)
fatal("Missing terminator for " block_current() " block")
print "#endif /* __ASM_SYSREG_DEFS_H */" print "#endif /* __ASM_SYSREG_DEFS_H */"
} }
...@@ -95,8 +111,9 @@ END { ...@@ -95,8 +111,9 @@ END {
/^$/ { next } /^$/ { next }
/^[\t ]*#/ { next } /^[\t ]*#/ { next }
/^SysregFields/ { /^SysregFields/ && block_current() == "Root" {
change_block("SysregFields", "None", "SysregFields") block_push("SysregFields")
expect_fields(2) expect_fields(2)
reg = $2 reg = $2
...@@ -110,12 +127,10 @@ END { ...@@ -110,12 +127,10 @@ END {
next next
} }
/^EndSysregFields/ { /^EndSysregFields/ && block_current() == "SysregFields" {
if (next_bit > 0) if (next_bit > 0)
fatal("Unspecified bits in " reg) fatal("Unspecified bits in " reg)
change_block("EndSysregFields", "SysregFields", "None")
define(reg "_RES0", "(" res0 ")") define(reg "_RES0", "(" res0 ")")
define(reg "_RES1", "(" res1 ")") define(reg "_RES1", "(" res1 ")")
define(reg "_UNKN", "(" unkn ")") define(reg "_UNKN", "(" unkn ")")
...@@ -126,11 +141,13 @@ END { ...@@ -126,11 +141,13 @@ END {
res1 = null res1 = null
unkn = null unkn = null
block_pop()
next next
} }
/^Sysreg/ { /^Sysreg/ && block_current() == "Root" {
change_block("Sysreg", "None", "Sysreg") block_push("Sysreg")
expect_fields(7) expect_fields(7)
reg = $2 reg = $2
...@@ -160,12 +177,10 @@ END { ...@@ -160,12 +177,10 @@ END {
next next
} }
/^EndSysreg/ { /^EndSysreg/ && block_current() == "Sysreg" {
if (next_bit > 0) if (next_bit > 0)
fatal("Unspecified bits in " reg) fatal("Unspecified bits in " reg)
change_block("EndSysreg", "Sysreg", "None")
if (res0 != null) if (res0 != null)
define(reg "_RES0", "(" res0 ")") define(reg "_RES0", "(" res0 ")")
if (res1 != null) if (res1 != null)
...@@ -185,12 +200,13 @@ END { ...@@ -185,12 +200,13 @@ END {
res1 = null res1 = null
unkn = null unkn = null
block_pop()
next next
} }
# Currently this is effectivey a comment, in future we may want to emit # Currently this is effectivey a comment, in future we may want to emit
# defines for the fields. # defines for the fields.
/^Fields/ && (block == "Sysreg") { /^Fields/ && block_current() == "Sysreg" {
expect_fields(2) expect_fields(2)
if (next_bit != 63) if (next_bit != 63)
...@@ -208,7 +224,7 @@ END { ...@@ -208,7 +224,7 @@ END {
} }
/^Res0/ && (block == "Sysreg" || block == "SysregFields") { /^Res0/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
expect_fields(2) expect_fields(2)
parse_bitdef(reg, "RES0", $2) parse_bitdef(reg, "RES0", $2)
field = "RES0_" msb "_" lsb field = "RES0_" msb "_" lsb
...@@ -218,7 +234,7 @@ END { ...@@ -218,7 +234,7 @@ END {
next next
} }
/^Res1/ && (block == "Sysreg" || block == "SysregFields") { /^Res1/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
expect_fields(2) expect_fields(2)
parse_bitdef(reg, "RES1", $2) parse_bitdef(reg, "RES1", $2)
field = "RES1_" msb "_" lsb field = "RES1_" msb "_" lsb
...@@ -228,7 +244,7 @@ END { ...@@ -228,7 +244,7 @@ END {
next next
} }
/^Unkn/ && (block == "Sysreg" || block == "SysregFields") { /^Unkn/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
expect_fields(2) expect_fields(2)
parse_bitdef(reg, "UNKN", $2) parse_bitdef(reg, "UNKN", $2)
field = "UNKN_" msb "_" lsb field = "UNKN_" msb "_" lsb
...@@ -238,7 +254,7 @@ END { ...@@ -238,7 +254,7 @@ END {
next next
} }
/^Field/ && (block == "Sysreg" || block == "SysregFields") { /^Field/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
expect_fields(3) expect_fields(3)
field = $3 field = $3
parse_bitdef(reg, field, $2) parse_bitdef(reg, field, $2)
...@@ -249,15 +265,16 @@ END { ...@@ -249,15 +265,16 @@ END {
next next
} }
/^Raz/ && (block == "Sysreg" || block == "SysregFields") { /^Raz/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
expect_fields(2) expect_fields(2)
parse_bitdef(reg, field, $2) parse_bitdef(reg, field, $2)
next next
} }
/^SignedEnum/ { /^SignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
change_block("Enum<", "Sysreg", "Enum") block_push("Enum")
expect_fields(3) expect_fields(3)
field = $3 field = $3
parse_bitdef(reg, field, $2) parse_bitdef(reg, field, $2)
...@@ -268,8 +285,9 @@ END { ...@@ -268,8 +285,9 @@ END {
next next
} }
/^UnsignedEnum/ { /^UnsignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
change_block("Enum<", "Sysreg", "Enum") block_push("Enum")
expect_fields(3) expect_fields(3)
field = $3 field = $3
parse_bitdef(reg, field, $2) parse_bitdef(reg, field, $2)
...@@ -280,8 +298,9 @@ END { ...@@ -280,8 +298,9 @@ END {
next next
} }
/^Enum/ { /^Enum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
change_block("Enum", "Sysreg", "Enum") block_push("Enum")
expect_fields(3) expect_fields(3)
field = $3 field = $3
parse_bitdef(reg, field, $2) parse_bitdef(reg, field, $2)
...@@ -291,16 +310,18 @@ END { ...@@ -291,16 +310,18 @@ END {
next next
} }
/^EndEnum/ { /^EndEnum/ && block_current() == "Enum" {
change_block("EndEnum", "Enum", "Sysreg")
field = null field = null
msb = null msb = null
lsb = null lsb = null
print "" print ""
block_pop()
next next
} }
/0b[01]+/ && block == "Enum" { /0b[01]+/ && block_current() == "Enum" {
expect_fields(2) expect_fields(2)
val = $1 val = $1
name = $2 name = $2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment