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 function block_current() { 8 return __current_block[__current_block_depth]; 9 } 10 11 # Log an error and terminate 12 function fatal(msg) { 13 print "Error at " NR ": " msg > "/dev/stderr" 14 15 printf "Current block nesting:" 16 17 for (i = 0; i <= __current_block_depth; i++) { 18 printf " " __current_block[i] 19 } 20 printf "\n" 21 22 exit 1 23 } 24 25 # Enter a new block, setting the active block to @block 26 function block_push(block) { 27 __current_block[++__current_block_depth] = block 28 } 29 30 # Exit a block, setting the active block to the parent block 31 function block_pop() { 32 if (__current_block_depth == 0) 33 fatal("error: block_pop() in root block") 34 35 __current_block_depth--; 36 } 37 38 # Sanity check the number of records for a field makes sense. If not, produce 39 # an error and terminate. 40 function expect_fields(nf) { 41 if (NF != nf) 42 fatal(NF " fields found where " nf " expected") 43 } 44 45 # Print a CPP macro definition, padded with spaces so that the macro bodies 46 # line up in a column 47 function define(name, val) { 48 printf "%-56s%s\n", "#define " name, val 49 } 50 51 # Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field 52 function define_field(reg, field, msb, lsb) { 53 define(reg "_" field, "GENMASK(" msb ", " lsb ")") 54 define(reg "_" field "_MASK", "GENMASK(" msb ", " lsb ")") 55 define(reg "_" field "_SHIFT", lsb) 56 define(reg "_" field "_WIDTH", msb - lsb + 1) 57 } 58 59 # Print a field _SIGNED definition for a field 60 function define_field_sign(reg, field, sign) { 61 define(reg "_" field "_SIGNED", sign) 62 } 63 64 # Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb 65 function parse_bitdef(reg, field, bitdef, _bits) 66 { 67 if (bitdef ~ /^[0-9]+$/) { 68 msb = bitdef 69 lsb = bitdef 70 } else if (split(bitdef, _bits, ":") == 2) { 71 msb = _bits[1] 72 lsb = _bits[2] 73 } else { 74 fatal("invalid bit-range definition '" bitdef "'") 75 } 76 77 78 if (msb != next_bit) 79 fatal(reg "." field " starts at " msb " not " next_bit) 80 if (63 < msb || msb < 0) 81 fatal(reg "." field " invalid high bit in '" bitdef "'") 82 if (63 < lsb || lsb < 0) 83 fatal(reg "." field " invalid low bit in '" bitdef "'") 84 if (msb < lsb) 85 fatal(reg "." field " invalid bit-range '" bitdef "'") 86 if (low > high) 87 fatal(reg "." field " has invalid range " high "-" low) 88 89 next_bit = lsb - 1 90 } 91 92 BEGIN { 93 print "#ifndef __ASM_SYSREG_DEFS_H" 94 print "#define __ASM_SYSREG_DEFS_H" 95 print "" 96 print "/* Generated file - do not edit */" 97 print "" 98 99 __current_block_depth = 0 100 __current_block[__current_block_depth] = "Root" 101 } 102 103 END { 104 if (__current_block_depth != 0) 105 fatal("Missing terminator for " block_current() " block") 106 107 print "#endif /* __ASM_SYSREG_DEFS_H */" 108 } 109 110 # skip blank lines and comment lines 111 /^$/ { next } 112 /^[\t ]*#/ { next } 113 114 /^SysregFields/ && block_current() == "Root" { 115 block_push("SysregFields") 116 117 expect_fields(2) 118 119 reg = $2 120 121 res0 = "UL(0)" 122 res1 = "UL(0)" 123 unkn = "UL(0)" 124 125 next_bit = 63 126 127 next 128 } 129 130 /^EndSysregFields/ && block_current() == "SysregFields" { 131 if (next_bit > 0) 132 fatal("Unspecified bits in " reg) 133 134 define(reg "_RES0", "(" res0 ")") 135 define(reg "_RES1", "(" res1 ")") 136 define(reg "_UNKN", "(" unkn ")") 137 print "" 138 139 reg = null 140 res0 = null 141 res1 = null 142 unkn = null 143 144 block_pop() 145 next 146 } 147 148 /^Sysreg/ && block_current() == "Root" { 149 block_push("Sysreg") 150 151 expect_fields(7) 152 153 reg = $2 154 op0 = $3 155 op1 = $4 156 crn = $5 157 crm = $6 158 op2 = $7 159 160 res0 = "UL(0)" 161 res1 = "UL(0)" 162 unkn = "UL(0)" 163 164 define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2) 165 define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")") 166 167 define("SYS_" reg "_Op0", op0) 168 define("SYS_" reg "_Op1", op1) 169 define("SYS_" reg "_CRn", crn) 170 define("SYS_" reg "_CRm", crm) 171 define("SYS_" reg "_Op2", op2) 172 173 print "" 174 175 next_bit = 63 176 177 next 178 } 179 180 /^EndSysreg/ && block_current() == "Sysreg" { 181 if (next_bit > 0) 182 fatal("Unspecified bits in " reg) 183 184 if (res0 != null) 185 define(reg "_RES0", "(" res0 ")") 186 if (res1 != null) 187 define(reg "_RES1", "(" res1 ")") 188 if (unkn != null) 189 define(reg "_UNKN", "(" unkn ")") 190 if (res0 != null || res1 != null || unkn != null) 191 print "" 192 193 reg = null 194 op0 = null 195 op1 = null 196 crn = null 197 crm = null 198 op2 = null 199 res0 = null 200 res1 = null 201 unkn = null 202 203 block_pop() 204 next 205 } 206 207 # Currently this is effectivey a comment, in future we may want to emit 208 # defines for the fields. 209 /^Fields/ && block_current() == "Sysreg" { 210 expect_fields(2) 211 212 if (next_bit != 63) 213 fatal("Some fields already defined for " reg) 214 215 print "/* For " reg " fields see " $2 " */" 216 print "" 217 218 next_bit = 0 219 res0 = null 220 res1 = null 221 unkn = null 222 223 next 224 } 225 226 227 /^Res0/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 228 expect_fields(2) 229 parse_bitdef(reg, "RES0", $2) 230 field = "RES0_" msb "_" lsb 231 232 res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")" 233 234 next 235 } 236 237 /^Res1/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 238 expect_fields(2) 239 parse_bitdef(reg, "RES1", $2) 240 field = "RES1_" msb "_" lsb 241 242 res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")" 243 244 next 245 } 246 247 /^Unkn/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 248 expect_fields(2) 249 parse_bitdef(reg, "UNKN", $2) 250 field = "UNKN_" msb "_" lsb 251 252 unkn = unkn " | GENMASK_ULL(" msb ", " lsb ")" 253 254 next 255 } 256 257 /^Field/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 258 expect_fields(3) 259 field = $3 260 parse_bitdef(reg, field, $2) 261 262 define_field(reg, field, msb, lsb) 263 print "" 264 265 next 266 } 267 268 /^Raz/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 269 expect_fields(2) 270 parse_bitdef(reg, field, $2) 271 272 next 273 } 274 275 /^SignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 276 block_push("Enum") 277 278 expect_fields(3) 279 field = $3 280 parse_bitdef(reg, field, $2) 281 282 define_field(reg, field, msb, lsb) 283 define_field_sign(reg, field, "true") 284 285 next 286 } 287 288 /^UnsignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 289 block_push("Enum") 290 291 expect_fields(3) 292 field = $3 293 parse_bitdef(reg, field, $2) 294 295 define_field(reg, field, msb, lsb) 296 define_field_sign(reg, field, "false") 297 298 next 299 } 300 301 /^Enum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 302 block_push("Enum") 303 304 expect_fields(3) 305 field = $3 306 parse_bitdef(reg, field, $2) 307 308 define_field(reg, field, msb, lsb) 309 310 next 311 } 312 313 /^EndEnum/ && block_current() == "Enum" { 314 315 field = null 316 msb = null 317 lsb = null 318 print "" 319 320 block_pop() 321 next 322 } 323 324 /0b[01]+/ && block_current() == "Enum" { 325 expect_fields(2) 326 val = $1 327 name = $2 328 329 define(reg "_" field "_" name, "UL(" val ")") 330 next 331 } 332 333 # Any lines not handled by previous rules are unexpected 334 { 335 fatal("unhandled statement") 336 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.