| #!/bin/awk -f | |
| # SPDX-License-Identifier: GPL-2.0 | |
| # gen-sysreg.awk: arm64 sysreg header generator | |
| # | |
| # Usage: awk -f gen-sysreg.awk sysregs.txt | |
| # Log an error and terminate | |
| function fatal(msg) { | |
| print "Error at " NR ": " msg > "/dev/stderr" | |
| exit 1 | |
| } | |
| # Sanity check that the start or end of a block makes sense at this point in | |
| # the file. If not, produce an error and terminate. | |
| # | |
| # @this - the $Block or $EndBlock | |
| # @prev - the only valid block to already be in (value of @block) | |
| # @new - the new value of @block | |
| function change_block(this, prev, new) { | |
| if (block != prev) | |
| fatal("unexpected " this " (inside " block ")") | |
| block = new | |
| } | |
| # 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 "%-48s%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) | |
| } | |
| # 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 "" | |
| block = "None" | |
| } | |
| END { | |
| print "#endif /* __ASM_SYSREG_DEFS_H */" | |
| } | |
| # skip blank lines and comment lines | |
| /^$/ { next } | |
| /^[\t ]*#/ { next } | |
| /^SysregFields/ { | |
| change_block("SysregFields", "None", "SysregFields") | |
| expect_fields(2) | |
| reg = $2 | |
| res0 = "UL(0)" | |
| res1 = "UL(0)" | |
| next_bit = 63 | |
| next | |
| } | |
| /^EndSysregFields/ { | |
| if (next_bit > 0) | |
| fatal("Unspecified bits in " reg) | |
| change_block("EndSysregFields", "SysregFields", "None") | |
| define(reg "_RES0", "(" res0 ")") | |
| define(reg "_RES1", "(" res1 ")") | |
| print "" | |
| reg = null | |
| res0 = null | |
| res1 = null | |
| next | |
| } | |
| /^Sysreg/ { | |
| change_block("Sysreg", "None", "Sysreg") | |
| expect_fields(7) | |
| reg = $2 | |
| op0 = $3 | |
| op1 = $4 | |
| crn = $5 | |
| crm = $6 | |
| op2 = $7 | |
| res0 = "UL(0)" | |
| res1 = "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/ { | |
| if (next_bit > 0) | |
| fatal("Unspecified bits in " reg) | |
| change_block("EndSysreg", "Sysreg", "None") | |
| if (res0 != null) | |
| define(reg "_RES0", "(" res0 ")") | |
| if (res1 != null) | |
| define(reg "_RES1", "(" res1 ")") | |
| if (res0 != null || res1 != null) | |
| print "" | |
| reg = null | |
| op0 = null | |
| op1 = null | |
| crn = null | |
| crm = null | |
| op2 = null | |
| res0 = null | |
| res1 = null | |
| next | |
| } | |
| # Currently this is effectivey a comment, in future we may want to emit | |
| # defines for the fields. | |
| /^Fields/ && (block == "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 | |
| next | |
| } | |
| /^Res0/ && (block == "Sysreg" || block == "SysregFields") { | |
| expect_fields(2) | |
| parse_bitdef(reg, "RES0", $2) | |
| field = "RES0_" msb "_" lsb | |
| res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")" | |
| next | |
| } | |
| /^Res1/ && (block == "Sysreg" || block == "SysregFields") { | |
| expect_fields(2) | |
| parse_bitdef(reg, "RES1", $2) | |
| field = "RES1_" msb "_" lsb | |
| res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")" | |
| next | |
| } | |
| /^Field/ && (block == "Sysreg" || block == "SysregFields") { | |
| expect_fields(3) | |
| field = $3 | |
| parse_bitdef(reg, field, $2) | |
| define_field(reg, field, msb, lsb) | |
| print "" | |
| next | |
| } | |
| /^Raz/ && (block == "Sysreg" || block == "SysregFields") { | |
| expect_fields(2) | |
| parse_bitdef(reg, field, $2) | |
| next | |
| } | |
| /^Enum/ { | |
| change_block("Enum", "Sysreg", "Enum") | |
| expect_fields(3) | |
| field = $3 | |
| parse_bitdef(reg, field, $2) | |
| define_field(reg, field, msb, lsb) | |
| next | |
| } | |
| /^EndEnum/ { | |
| change_block("EndEnum", "Enum", "Sysreg") | |
| field = null | |
| msb = null | |
| lsb = null | |
| print "" | |
| next | |
| } | |
| /0b[01]+/ && block == "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") | |
| } |