| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- #!/bin/awk -f
- # SPDX-License-Identifier: GPL-2.0
- # gen-sysreg.awk: arm64 sysreg header generator
- #
- # Usage: awk -f gen-sysreg.awk sysregs.txt
- function block_current() {
- return __current_block[__current_block_depth];
- }
- # Log an error and terminate
- function fatal(msg) {
- 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
- }
- # Enter a new block, setting the active block to @block
- function block_push(block) {
- __current_block[++__current_block_depth] = block
- }
- # Exit a block, setting the active block to the parent block
- function block_pop() {
- if (__current_block_depth == 0)
- fatal("error: block_pop() in root block")
- __current_block_depth--;
- }
- # Sanity check the number of records for a field makes sense. If not, produce
- # an error and terminate.
- function expect_fields(nf) {
- if (NF != nf)
- fatal(NF " fields found where " nf " expected")
- }
- # Print a CPP macro definition, padded with spaces so that the macro bodies
- # line up in a column
- function define(name, val) {
- printf "%-56s%s\n", "#define " name, val
- }
- # Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field
- function define_field(reg, field, msb, lsb) {
- define(reg "_" field, "GENMASK(" msb ", " lsb ")")
- define(reg "_" field "_MASK", "GENMASK(" msb ", " lsb ")")
- define(reg "_" field "_SHIFT", lsb)
- define(reg "_" field "_WIDTH", msb - lsb + 1)
- }
- # Print a field _SIGNED definition for a field
- function define_field_sign(reg, field, sign) {
- define(reg "_" field "_SIGNED", sign)
- }
- # Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb
- function parse_bitdef(reg, field, bitdef, _bits)
- {
- if (bitdef ~ /^[0-9]+$/) {
- msb = bitdef
- lsb = bitdef
- } else if (split(bitdef, _bits, ":") == 2) {
- msb = _bits[1]
- lsb = _bits[2]
- } else {
- fatal("invalid bit-range definition '" bitdef "'")
- }
- if (msb != next_bit)
- fatal(reg "." field " starts at " msb " not " next_bit)
- if (63 < msb || msb < 0)
- fatal(reg "." field " invalid high bit in '" bitdef "'")
- if (63 < lsb || lsb < 0)
- fatal(reg "." field " invalid low bit in '" bitdef "'")
- if (msb < lsb)
- fatal(reg "." field " invalid bit-range '" bitdef "'")
- if (low > high)
- fatal(reg "." field " has invalid range " high "-" low)
- next_bit = lsb - 1
- }
- BEGIN {
- print "#ifndef __ASM_SYSREG_DEFS_H"
- print "#define __ASM_SYSREG_DEFS_H"
- print ""
- print "/* Generated file - do not edit */"
- print ""
- __current_block_depth = 0
- __current_block[__current_block_depth] = "Root"
- }
- END {
- if (__current_block_depth != 0)
- fatal("Missing terminator for " block_current() " block")
- print "#endif /* __ASM_SYSREG_DEFS_H */"
- }
- # skip blank lines and comment lines
- /^$/ { next }
- /^[\t ]*#/ { next }
- /^SysregFields/ && block_current() == "Root" {
- block_push("SysregFields")
- expect_fields(2)
- reg = $2
- res0 = "UL(0)"
- res1 = "UL(0)"
- unkn = "UL(0)"
- next_bit = 63
- next
- }
- /^EndSysregFields/ && block_current() == "SysregFields" {
- if (next_bit > 0)
- fatal("Unspecified bits in " reg)
- define(reg "_RES0", "(" res0 ")")
- define(reg "_RES1", "(" res1 ")")
- define(reg "_UNKN", "(" unkn ")")
- print ""
- reg = null
- res0 = null
- res1 = null
- unkn = null
- block_pop()
- next
- }
- /^Sysreg/ && block_current() == "Root" {
- block_push("Sysreg")
- expect_fields(7)
- reg = $2
- op0 = $3
- op1 = $4
- crn = $5
- crm = $6
- op2 = $7
- res0 = "UL(0)"
- res1 = "UL(0)"
- unkn = "UL(0)"
- define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2)
- define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")")
- define("SYS_" reg "_Op0", op0)
- define("SYS_" reg "_Op1", op1)
- define("SYS_" reg "_CRn", crn)
- define("SYS_" reg "_CRm", crm)
- define("SYS_" reg "_Op2", op2)
- print ""
- next_bit = 63
- next
- }
- /^EndSysreg/ && block_current() == "Sysreg" {
- if (next_bit > 0)
- fatal("Unspecified bits in " reg)
- if (res0 != null)
- define(reg "_RES0", "(" res0 ")")
- if (res1 != null)
- define(reg "_RES1", "(" res1 ")")
- if (unkn != null)
- define(reg "_UNKN", "(" unkn ")")
- if (res0 != null || res1 != null || unkn != null)
- print ""
- reg = null
- op0 = null
- op1 = null
- crn = null
- crm = null
- op2 = null
- res0 = null
- res1 = null
- unkn = null
- block_pop()
- next
- }
- # Currently this is effectivey a comment, in future we may want to emit
- # defines for the fields.
- /^Fields/ && block_current() == "Sysreg" {
- expect_fields(2)
- if (next_bit != 63)
- fatal("Some fields already defined for " reg)
- print "/* For " reg " fields see " $2 " */"
- print ""
- next_bit = 0
- res0 = null
- res1 = null
- unkn = null
- next
- }
- /^Res0/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- expect_fields(2)
- parse_bitdef(reg, "RES0", $2)
- field = "RES0_" msb "_" lsb
- res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")"
- next
- }
- /^Res1/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- expect_fields(2)
- parse_bitdef(reg, "RES1", $2)
- field = "RES1_" msb "_" lsb
- res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")"
- next
- }
- /^Unkn/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- expect_fields(2)
- parse_bitdef(reg, "UNKN", $2)
- field = "UNKN_" msb "_" lsb
- unkn = unkn " | GENMASK_ULL(" msb ", " lsb ")"
- next
- }
- /^Field/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- expect_fields(3)
- field = $3
- parse_bitdef(reg, field, $2)
- define_field(reg, field, msb, lsb)
- print ""
- next
- }
- /^Raz/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- expect_fields(2)
- parse_bitdef(reg, field, $2)
- next
- }
- /^SignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- block_push("Enum")
- expect_fields(3)
- field = $3
- parse_bitdef(reg, field, $2)
- define_field(reg, field, msb, lsb)
- define_field_sign(reg, field, "true")
- next
- }
- /^UnsignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- block_push("Enum")
- expect_fields(3)
- field = $3
- parse_bitdef(reg, field, $2)
- define_field(reg, field, msb, lsb)
- define_field_sign(reg, field, "false")
- next
- }
- /^Enum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") {
- block_push("Enum")
- expect_fields(3)
- field = $3
- parse_bitdef(reg, field, $2)
- define_field(reg, field, msb, lsb)
- next
- }
- /^EndEnum/ && block_current() == "Enum" {
- field = null
- msb = null
- lsb = null
- print ""
- block_pop()
- next
- }
- /0b[01]+/ && block_current() == "Enum" {
- expect_fields(2)
- val = $1
- name = $2
- define(reg "_" field "_" name, "UL(" val ")")
- next
- }
- # Any lines not handled by previous rules are unexpected
- {
- fatal("unhandled statement")
- }
|