1#!/usr/bin/awk -f 2 3#- 4# Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer, 12# without modification. 13# 2. Redistributions in binary form must reproduce at minimum a disclaimer 14# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15# redistribution must be conditioned upon including a substantially 16# similar Disclaimer requirement for further binary redistribution. 17# 18# NO WARRANTY 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29# THE POSSIBILITY OF SUCH DAMAGES. 30# 31# $FreeBSD$ 32 33BEGIN { 34 RS="\n" 35 36 depth = 0 37 symbols[depth,"_file"] = FILENAME 38 num_output_vars = 0 39 OUTPUT_FILE = null 40 41 # Seed rand() 42 srand() 43 44 # Output type 45 OUT_T = null 46 OUT_T_HEADER = "HEADER" 47 OUT_T_DATA = "DATA" 48 49 # Enable debug output 50 DEBUG = 0 51 52 # Maximum revision 53 REV_MAX = 255 54 55 # Parse arguments 56 if (ARGC < 2) 57 usage() 58 59 for (i = 1; i < ARGC; i++) { 60 if (ARGV[i] == "--debug") { 61 DEBUG = 1 62 } else if (ARGV[i] == "-d" && OUT_T == null) { 63 OUT_T = OUT_T_DATA 64 } else if (ARGV[i] == "-h" && OUT_T == null) { 65 OUT_T = OUT_T_HEADER 66 } else if (ARGV[i] == "-o") { 67 i++ 68 if (i >= ARGC) 69 usage() 70 71 OUTPUT_FILE = ARGV[i] 72 } else if (ARGV[i] == "--") { 73 i++ 74 break 75 } else if (ARGV[i] !~ /^-/) { 76 FILENAME = ARGV[i] 77 } else { 78 print "unknown option " ARGV[i] 79 usage() 80 } 81 } 82 83 ARGC=2 84 85 if (OUT_T == null) { 86 print("error: one of -d or -h required") 87 usage() 88 } 89 90 if (FILENAME == null) { 91 print("error: no input file specified") 92 usage() 93 } 94 95 if (OUTPUT_FILE == "-") { 96 OUTPUT_FILE = "/dev/stdout" 97 } else if (OUTPUT_FILE == null) { 98 _bi = split(FILENAME, _paths, "/") 99 OUTPUT_FILE = _paths[_bi] 100 101 if (OUTPUT_FILE !~ /^bhnd_/) 102 OUTPUT_FILE = "bhnd_" OUTPUT_FILE 103 104 if (OUT_T == OUT_T_HEADER) 105 OUTPUT_FILE = OUTPUT_FILE ".h" 106 else 107 OUTPUT_FILE = OUTPUT_FILE "_data.h" 108 } 109 110 # Format Constants 111 FMT["hex"] = "BHND_NVRAM_VFMT_HEX" 112 FMT["decimal"] = "BHND_NVRAM_VFMT_DEC" 113 FMT["ccode"] = "BHND_NVRAM_VFMT_CCODE" 114 FMT["macaddr"] = "BHND_NVRAM_VFMT_MACADDR" 115 FMT["led_dc"] = "BHND_NVRAM_VFMT_LEDDC" 116 117 # Data Type Constants 118 DTYPE["u8"] = "BHND_NVRAM_DT_UINT8" 119 DTYPE["u16"] = "BHND_NVRAM_DT_UINT16" 120 DTYPE["u32"] = "BHND_NVRAM_DT_UINT32" 121 DTYPE["i8"] = "BHND_NVRAM_DT_INT8" 122 DTYPE["i16"] = "BHND_NVRAM_DT_INT16" 123 DTYPE["i32"] = "BHND_NVRAM_DT_INT32" 124 DTYPE["char"] = "BHND_NVRAM_DT_CHAR" 125 126 # Default masking for standard types 127 TMASK["u8"] = "0x000000FF" 128 TMASK["u16"] = "0x0000FFFF" 129 TMASK["u32"] = "0xFFFFFFFF" 130 TMASK["i8"] = TMASK["u8"] 131 TMASK["i16"] = TMASK["u16"] 132 TMASK["i32"] = TMASK["u32"] 133 TMASK["char"] = TMASK["u8"] 134 135 # Byte sizes for standard types 136 TSIZE["u8"] = "1" 137 TSIZE["u16"] = "2" 138 TSIZE["u32"] = "4" 139 TSIZE["i8"] = TSIZE["u8"] 140 TSIZE["i16"] = TSIZE["u8"] 141 TSIZE["i32"] = TSIZE["u8"] 142 TSIZE["char"] = "1" 143 144 # Common Regexs 145 INT_REGEX = "^(0|[1-9][0-9]*),?$" 146 HEX_REGEX = "^0x[A-Fa-f0-9]+,?$" 147 148 ARRAY_REGEX = "\\[(0|[1-9][0-9]*)\\]" 149 TYPES_REGEX = "^(((u|i)(8|16|32))|char)("ARRAY_REGEX")?,?$" 150 151 IDENT_REGEX = "^[A-Za-z_][A-Za-z0-9_]*,?$" 152 SROM_OFF_REGEX = "("TYPES_REGEX"|"HEX_REGEX")" 153 154 # Parser states types 155 ST_STRUCT_BLOCK = "struct" # struct block 156 ST_VAR_BLOCK = "var" # variable block 157 ST_SROM_DEFN = "srom" # srom offset defn 158 ST_NONE = "NONE" # default state 159 160 # Property types 161 PROP_T_SFMT = "sfmt" 162 PROP_T_ALL1 = "all1" 163 164 # Internal variables used for parser state 165 # tracking 166 STATE_TYPE = "_state_type" 167 STATE_IDENT = "_state_block_name" 168 STATE_LINENO = "_state_first_line" 169 STATE_ISBLOCK = "_state_is_block" 170 171 # Common array keys 172 DEF_LINE = "def_line" 173 NUM_REVS = "num_revs" 174 REV = "rev" 175 176 # Revision array keys 177 REV_START = "rev_start" 178 REV_END = "rev_end" 179 REV_DESC = "rev_decl" 180 REV_NUM_OFFS = "num_offs" 181 182 # Offset array keys 183 OFF = "off" 184 OFF_NUM_SEGS = "off_num_segs" 185 OFF_SEG = "off_seg" 186 187 # Segment array keys 188 SEG_ADDR = "seg_addr" 189 SEG_COUNT = "seg_count" 190 SEG_TYPE = "seg_type" 191 SEG_MASK = "seg_mask" 192 SEG_SHIFT = "seg_shift" 193 194 # Variable array keys 195 VAR_NAME = "v_name" 196 VAR_TYPE = "v_type" 197 VAR_BASE_TYPE = "v_base_type" 198 VAR_FMT = "v_fmt" 199 VAR_STRUCT = "v_parent_struct" 200 VAR_PRIVATE = "v_private" 201 VAR_ARRAY = "v_array" 202 VAR_IGNALL1 = "v_ignall1" 203} 204 205# return the flag definition for variable `v` 206function gen_var_flags (v) 207{ 208 _num_flags = 0; 209 if (vars[v,VAR_ARRAY]) 210 _flags[_num_flags++] = "BHND_NVRAM_VF_ARRAY" 211 212 if (vars[v,VAR_PRIVATE]) 213 _flags[_num_flags++] = "BHND_NVRAM_VF_MFGINT" 214 215 if (vars[v,VAR_IGNALL1]) 216 _flags[_num_flags++] = "BHND_NVRAM_VF_IGNALL1" 217 218 if (_num_flags == 0) 219 _flags[_num_flags++] = "0" 220 221 return (join(_flags, "|", _num_flags)) 222} 223 224# emit the bhnd_sprom_offsets for a given variable revision key 225function emit_var_sprom_offsets (v, revk) 226{ 227 emit(sprintf("{{%u, %u}, (struct bhnd_sprom_offset[]) {\n", 228 vars[revk,REV_START], 229 vars[revk,REV_END])) 230 output_depth++ 231 232 num_offs = vars[revk,REV_NUM_OFFS] 233 num_offs_written = 0 234 elem_count = 0 235 for (offset = 0; offset < num_offs; offset++) { 236 offk = subkey(revk, OFF, offset"") 237 num_segs = vars[offk,OFF_NUM_SEGS] 238 239 for (seg = 0; seg < num_segs; seg++) { 240 segk = subkey(offk, OFF_SEG, seg"") 241 242 for (seg_n = 0; seg_n < vars[segk,SEG_COUNT]; seg_n++) { 243 seg_addr = vars[segk,SEG_ADDR] 244 seg_addr += TSIZE[vars[segk,SEG_TYPE]] * seg_n 245 246 emit(sprintf("{%s, %s, %s, %s, %s},\n", 247 seg_addr, 248 (seg > 0) ? "true" : "false", 249 DTYPE[vars[segk,SEG_TYPE]], 250 vars[segk,SEG_SHIFT], 251 vars[segk,SEG_MASK])) 252 253 num_offs_written++ 254 } 255 } 256 } 257 258 output_depth-- 259 emit("}, " num_offs_written "},\n") 260} 261 262# emit the bhnd_nvram_var definition for variable name `v` 263function emit_var_defn (v) 264{ 265 emit(sprintf("{\"%s\", %s, %s, %s, (struct bhnd_sprom_var[]) {\n", 266 v suffix, 267 DTYPE[vars[v,VAR_BASE_TYPE]], 268 FMT[vars[v,VAR_FMT]], 269 gen_var_flags(v))) 270 output_depth++ 271 272 for (rev = 0; rev < vars[v,NUM_REVS]; rev++) { 273 revk = subkey(v, REV, rev"") 274 emit_var_sprom_offsets(v, revk) 275 } 276 277 output_depth-- 278 emit("}, " vars[v,NUM_REVS] "},\n") 279} 280 281# emit a header name #define for variable `v` 282function emit_var_namedef (v) 283{ 284 emit("#define\tBHND_NVAR_" toupper(v) "\t\"" v "\"\n") 285} 286 287# generate a set of var offset definitions for struct variable `st_vid` 288function gen_struct_var_offsets (vid, revk, st_vid, st_revk, base_addr) 289{ 290 # Copy all offsets to the new variable 291 for (offset = 0; offset < vars[v,REV_NUM_OFFS]; offset++) { 292 st_offk = subkey(st_revk, OFF, offset"") 293 offk = subkey(revk, OFF, offset"") 294 295 # Copy all segments to the new variable, applying base 296 # address adjustment 297 num_segs = vars[st_offk,OFF_NUM_SEGS] 298 vars[offk,OFF_NUM_SEGS] = num_segs 299 300 for (seg = 0; seg < num_segs; seg++) { 301 st_segk = subkey(st_offk, OFF_SEG, seg"") 302 segk = subkey(offk, OFF_SEG, seg"") 303 304 vars[segk,SEG_ADDR] = vars[st_segk,SEG_ADDR] + \ 305 base_addr"" 306 vars[segk,SEG_COUNT] = vars[st_segk,SEG_COUNT] 307 vars[segk,SEG_TYPE] = vars[st_segk,SEG_TYPE] 308 vars[segk,SEG_MASK] = vars[st_segk,SEG_MASK] 309 vars[segk,SEG_SHIFT] = vars[st_segk,SEG_SHIFT] 310 } 311 } 312} 313 314# generate a complete set of variable definitions for struct variable `st_vid`. 315function gen_struct_vars (st_vid) 316{ 317 st = vars[st_vid,VAR_STRUCT] 318 st_max_off = 0 319 320 # determine the total number of variables to generate 321 for (st_rev = 0; st_rev < structs[st,NUM_REVS]; st_rev++) { 322 srevk = subkey(st, REV, st_rev"") 323 for (off = 0; off < structs[srevk,REV_NUM_OFFS]; off++) { 324 if (off > st_max_off) 325 st_max_off = off 326 } 327 } 328 329 # generate variable records for each defined struct offset 330 for (off = 0; off < st_max_off; off++) { 331 # Construct basic variable definition 332 v = st_vid off"" 333 vars[v,VAR_TYPE] = vars[st_vid,VAR_TYPE] 334 vars[v,VAR_BASE_TYPE] = vars[st_vid,VAR_BASE_TYPE] 335 vars[v,VAR_FMT] = vars[st_vid,VAR_FMT] 336 vars[v,VAR_PRIVATE] = vars[st_vid,VAR_PRIVATE] 337 vars[v,VAR_ARRAY] = vars[st_vid,VAR_ARRAY] 338 vars[v,VAR_IGNALL1] = vars[st_vid,VAR_IGNALL1] 339 vars[v,NUM_REVS] = 0 340 341 # Add to output variable list 342 output_vars[num_output_vars++] = v 343 344 # Construct revision / offset entries 345 for (srev = 0; srev < structs[st,NUM_REVS]; srev++) { 346 # Struct revision key 347 st_revk = subkey(st, REV, srev"") 348 349 # Skip offsets not defined for this revision 350 if (off > structs[st_revk,REV_NUM_OFFS]) 351 continue 352 353 # Strut offset key and associated base address */ 354 offk = subkey(st_revk, OFF, off"") 355 base_addr = structs[offk,SEG_ADDR] 356 357 for (vrev = 0; vrev < vars[st_vid,NUM_REVS]; vrev++) { 358 st_var_revk = subkey(st_vid, REV, vrev"") 359 v_start = vars[st_var_revk,REV_START] 360 v_end = vars[st_var_revk,REV_END] 361 s_start = structs[st_revk,REV_START] 362 s_end = structs[st_revk,REV_END] 363 364 # We don't support computing the union 365 # of partially overlapping ranges 366 if ((v_start < s_start && v_end >= s_start) || 367 (v_start <= s_end && v_end > s_end)) 368 { 369 errorx("partially overlapping " \ 370 "revision ranges are not supported") 371 } 372 373 # skip variables revs that are not within 374 # the struct offset's compatibility range 375 if (v_start < s_start || v_start > s_end || 376 v_end < s_start || v_end > s_end) 377 continue 378 379 # Generate the new revision record 380 rev = vars[v,NUM_REVS] "" 381 revk = subkey(v, REV, rev) 382 vars[v,NUM_REVS]++ 383 384 vars[revk,DEF_LINE] = vars[st_revk,DEF_LINE] 385 vars[revk,REV_START] = v_start 386 vars[revk,REV_END] = v_end 387 vars[revk,REV_NUM_OFFS] = \ 388 vars[st_var_revk,REV_NUM_OFFS] 389 390 gen_struct_var_offsets(v, revk, st_vid, st_revk, 391 base_addr) 392 } 393 } 394 } 395} 396 397 398END { 399 # Skip completion handling if exiting from an error 400 if (_EARLY_EXIT) 401 exit 1 402 403 # Check for complete block closure 404 if (depth > 0) { 405 block_start = g(STATE_LINENO) 406 errorx("missing '}' for block opened on line " block_start "") 407 } 408 409 # Generate concrete variable definitions for all struct variables 410 for (v in var_names) { 411 if (vars[v,VAR_STRUCT] != null) { 412 gen_struct_vars(v) 413 } else { 414 output_vars[num_output_vars++] = v 415 } 416 } 417 418 # Apply lexicographical sorting. To support more effecient table 419 # searching, we guarantee a stable sort order (using C collation). 420 sort(output_vars) 421 422 # Truncate output file and write common header 423 printf("") > OUTPUT_FILE 424 emit("/*\n") 425 emit(" * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.\n") 426 emit(" *\n") 427 emit(" * generated from nvram map: " FILENAME "\n") 428 emit(" */\n") 429 emit("\n") 430 431 # Emit all variable definitions 432 if (OUT_T == OUT_T_DATA) { 433 emit("#include <dev/bhnd/nvram/nvramvar.h>\n") 434 emit("static const struct bhnd_nvram_var bhnd_nvram_vars[] = "\ 435 "{\n") 436 output_depth++ 437 for (i = 0; i < num_output_vars; i++) 438 emit_var_defn(output_vars[i]) 439 output_depth-- 440 emit("};\n") 441 } else if (OUT_T == OUT_T_HEADER) { 442 for (i = 0; i < num_output_vars; i++) 443 emit_var_namedef(output_vars[i]) 444 } 445 446 printf("%u variable records written to %s\n", num_output_vars, 447 OUTPUT_FILE) >> "/dev/stderr" 448} 449 450 451# 452# Print usage 453# 454function usage () 455{ 456 print "usage: bhnd_nvram_map.awk <input map> [-hd] [-o output file]" 457 _EARLY_EXIT = 1 458 exit 1 459} 460 461# 462# Join all array elements with the given separator 463# 464function join (array, sep, count) 465{ 466 if (count == 0) 467 return ("") 468 469 _result = array[0] 470 for (_ji = 1; _ji < count; _ji++) 471 _result = _result sep array[_ji] 472 473 return (_result) 474} 475 476# 477# Sort a contiguous integer-indexed array, using standard awk comparison 478# operators over its values. 479# 480function sort (array) { 481 # determine array size 482 _sort_alen = 0 483 484 for (_ssort_key in array) 485 _sort_alen++ 486 487 if (_sort_alen <= 1) 488 return 489 490 # perform sort 491 _qsort(array, 0, _sort_alen-1) 492} 493 494function _qsort (array, first, last) 495{ 496 if (first >= last) 497 return 498 499 # select pivot element 500 _qpivot = int(first + int((last-first+1) * rand())) 501 _qleft = first 502 _qright = last 503 504 _qpivot_val = array[_qpivot] 505 506 # partition 507 while (_qleft <= _qright) { 508 while (array[_qleft] < _qpivot_val) 509 _qleft++ 510 511 while (array[_qright] > _qpivot_val) 512 _qright-- 513 514 # swap 515 if (_qleft <= _qright) { 516 _qleft_val = array[_qleft] 517 _qright_val = array[_qright] 518 519 array[_qleft] = _qright_val 520 array[_qright] = _qleft_val 521 522 _qleft++ 523 _qright-- 524 } 525 } 526 527 # sort the partitions 528 _qsort(array, first, _qright) 529 _qsort(array, _qleft, last) 530} 531 532# 533# Print msg to output file, without indentation 534# 535function emit_ni (msg) 536{ 537 printf("%s", msg) >> OUTPUT_FILE 538} 539 540# 541# Print msg to output file, indented for the current `output_depth` 542# 543function emit (msg) 544{ 545 for (_ind = 0; _ind < output_depth; _ind++) 546 emit_ni("\t") 547 548 emit_ni(msg) 549} 550 551# 552# Print a warning to stderr 553# 554function warn (msg) 555{ 556 print "warning:", msg, "at", FILENAME, "line", NR > "/dev/stderr" 557} 558 559# 560# Print a compiler error to stderr 561# 562function error (msg) 563{ 564 errorx(msg " at " FILENAME " line " NR ":\n\t" $0) 565} 566 567# 568# Print an error message without including the source line information 569# 570function errorx (msg) 571{ 572 print "error:", msg > "/dev/stderr" 573 _EARLY_EXIT=1 574 exit 1 575} 576 577# 578# Print a debug output message 579# 580function debug (msg) 581{ 582 if (!DEBUG) 583 return 584 for (_di = 0; _di < depth; _di++) 585 printf("\t") > "/dev/stderr" 586 print msg > "/dev/stderr" 587} 588 589# 590# Return an array key composed of the given (parent, selector, child) 591# tuple. 592# The child argument is optional and may be omitted. 593# 594function subkey (parent, selector, child) 595{ 596 if (child != null) 597 return (parent SUBSEP selector SUBSEP child) 598 else 599 return (parent SUBSEP selector) 600} 601 602# 603# Advance to the next non-comment input record 604# 605function next_line () 606{ 607 do { 608 _result = getline 609 } while (_result > 0 && $0 ~ /^[ \t]*#.*/) # skip comment lines 610 return (_result) 611} 612 613# 614# Advance to the next input record and verify that it matches @p regex 615# 616function getline_matching (regex) 617{ 618 _result = next_line() 619 if (_result <= 0) 620 return (_result) 621 622 if ($0 ~ regex) 623 return (1) 624 625 return (-1) 626} 627 628# 629# Shift the current fields left by `n`. 630# 631# If all fields are consumed and the optional do_getline argument is true, 632# read the next line. 633# 634function shiftf (n, do_getline) 635{ 636 if (n > NF) error("shift past end of line") 637 for (_si = 1; _si <= NF-n; _si++) { 638 $(_si) = $(_si+n) 639 } 640 NF = NF - n 641 642 if (NF == 0 && do_getline) 643 next_line() 644} 645 646# 647# Parse a revision descriptor from the current line. 648# 649function parse_revdesc (result) 650{ 651 _rstart = 0 652 _rend = 0 653 654 if ($2 ~ "[0-9]*-[0-9*]") { 655 split($2, _revrange, "[ \t]*-[ \t]*") 656 _rstart = _revrange[1] 657 _rend = _revrange[2] 658 } else if ($2 ~ "(>|>=|<|<=)" && $3 ~ "[1-9][0-9]*") { 659 if ($2 == ">") { 660 _rstart = int($3)+1 661 _rend = REV_MAX 662 } else if ($2 == ">=") { 663 _rstart = int($3) 664 _rend = REV_MAX 665 } else if ($2 == "<" && int($3) > 0) { 666 _rstart = 0 667 _rend = int($3)-1 668 } else if ($2 == "<=") { 669 _rstart = 0 670 _rend = int($3)-1 671 } else { 672 error("invalid revision descriptor") 673 } 674 } else if ($2 ~ "[1-9][0-9]*") { 675 _rstart = int($2) 676 _rend = int($2) 677 } else { 678 error("invalid revision descriptor") 679 } 680 681 result[REV_START] = _rstart 682 result[REV_END] = _rend 683} 684 685# 686# Push a new parser state. 687# 688# The name may be null, in which case the STATE_IDENT variable will not be 689# defined in this scope 690# 691function push_state (type, name, block) { 692 depth++ 693 push(STATE_LINENO, NR) 694 if (name != null) 695 push(STATE_IDENT, name) 696 push(STATE_TYPE, type) 697 push(STATE_ISBLOCK, block) 698} 699 700# 701# Pop the top of the parser state stack. 702# 703function pop_state () { 704 # drop all symbols defined at this depth 705 for (s in symbols) { 706 if (s ~ "^"depth"[^0-9]") 707 delete symbols[s] 708 } 709 depth-- 710} 711 712# 713# Find opening brace and push a new parser state for a brace-delimited block. 714# 715# The name may be null, in which case the STATE_IDENT variable will not be 716# defined in this scope 717# 718function open_block (type, name) 719{ 720 if ($0 ~ "{" || getline_matching("^[ \t]*{") > 0) { 721 push_state(type, name, 1) 722 sub("^[^{]+{", "", $0) 723 return 724 } 725 726 error("found '"$1 "' instead of expected '{' for '" name "'") 727} 728 729# 730# Find closing brace and pop parser states until the first 731# brace-delimited block is discarded. 732# 733function close_block () 734{ 735 if ($0 !~ "}") 736 error("internal error - no closing brace") 737 738 # pop states until we exit the first enclosing block 739 do { 740 _closed_block = g(STATE_ISBLOCK) 741 pop_state() 742 } while (!_closed_block) 743 744 # strip everything prior to the block closure 745 sub("^[^}]*}", "", $0) 746} 747 748# Internal symbol table lookup function. Returns the symbol depth if 749# name is found at or above scope; if scope is null, it defauls to 0 750function _find_sym (name, scope) 751{ 752 if (scope == null) 753 scope = 0; 754 755 for (i = scope; i < depth; i++) { 756 if ((depth-i,name) in symbols) 757 return (depth-i) 758 } 759 760 return (-1) 761} 762 763# 764# Look up a variable in the symbol table with `name` and return its value. 765# 766# If `scope` is not null, the variable search will start at the provided 767# scope level -- 0 is the current scope, 1 is the parent's scope, etc. 768# 769function g (name, scope) 770{ 771 _g_depth = _find_sym(name, scope) 772 if (_g_depth < 0) 773 error("'" name "' is undefined") 774 775 return (symbols[_g_depth,name]) 776} 777 778function is_defined (name, scope) 779{ 780 return (_find_sym(name, scope) >= 0) 781} 782 783# Define a new variable in the symbol table's current scope, 784# with the given value 785function push (name, value) 786{ 787 symbols[depth,name] = value 788} 789 790# Set an existing variable's value in the symbol table; if not yet defined, 791# will trigger an error 792function set (name, value, scope) 793{ 794 for (i = 0; i < depth; i++) { 795 if ((depth-i,name) in symbols) { 796 symbols[depth-i,name] = value 797 return 798 } 799 } 800 # No existing value, cannot define 801 error("'" name "' is undefined") 802} 803 804# Evaluates to true if immediately within a block scope of the given type 805function in_state (type) 806{ 807 if (!is_defined(STATE_TYPE)) 808 return (type == ST_NONE) 809 810 return (type == g(STATE_TYPE)) 811} 812 813# Evaluates to true if within an immediate or non-immediate block scope of the 814# given type 815function in_nested_state (type) 816{ 817 for (i = 0; i < depth; i++) { 818 if ((depth-i,STATE_TYPE) in symbols) { 819 if (symbols[depth-i,STATE_TYPE] == type) 820 return (1) 821 } 822 } 823 return (0) 824} 825 826# Evaluates to true if definitions of the given type are permitted within 827# the current scope 828function allow_def (type) 829{ 830 if (type == ST_VAR_BLOCK) { 831 return (in_state(ST_NONE) || in_state(ST_STRUCT_BLOCK)) 832 } else if (type == ST_STRUCT_BLOCK) { 833 return (in_state(ST_NONE)) 834 } else if (type == ST_SROM_DEFN) { 835 return (in_state(ST_VAR_BLOCK) || in_state(ST_STRUCT_BLOCK)) 836 } 837 838 error("unknown type '" type "'") 839} 840 841# struct definition 842$1 == ST_STRUCT_BLOCK && allow_def($1) { 843 name = $2 844 845 # Remove array[] specifier 846 if (sub(/\[\]$/, "", name) == 0) 847 error("expected '" name "[]', not '" name "'") 848 849 if (name !~ IDENT_REGEX || name ~ TYPES_REGEX) 850 error("invalid identifier '" name "'") 851 852 # Add top-level struct entry 853 if ((name,DEF_LINE) in structs) 854 error("struct identifier '" name "' previously defined on " \ 855 "line " structs[name,DEF_LINE]) 856 structs[name,DEF_LINE] = NR 857 structs[name,NUM_REVS] = 0 858 859 # Open the block 860 debug("struct " name " {") 861 open_block(ST_STRUCT_BLOCK, name) 862} 863 864# struct srom descriptor 865$1 == ST_SROM_DEFN && allow_def(ST_SROM_DEFN) && in_state(ST_STRUCT_BLOCK) { 866 sid = g(STATE_IDENT) 867 868 # parse revision descriptor 869 rev_desc[REV_START] = 0 870 parse_revdesc(rev_desc) 871 872 # assign revision id 873 rev = structs[sid,NUM_REVS] "" 874 revk = subkey(sid, REV, rev) 875 structs[sid,NUM_REVS]++ 876 877 # init basic revision state 878 structs[revk,REV_START] = rev_desc[REV_START] 879 structs[revk,REV_END] = rev_desc[REV_END] 880 881 if (match($0, "\\[[^]]*\\]") <= 0) 882 error("expected base address array") 883 884 addrs_str = substr($0, RSTART+1, RLENGTH-2) 885 num_offs = split(addrs_str, addrs, ",[ \t]*") 886 structs[revk, REV_NUM_OFFS] = num_offs 887 for (i = 1; i <= num_offs; i++) { 888 offk = subkey(revk, OFF, (i-1) "") 889 890 if (addrs[i] !~ HEX_REGEX) 891 error("invalid base address '" addrs[i] "'") 892 893 structs[offk,SEG_ADDR] = addrs[i] 894 } 895 896 debug("struct_srom " structs[revk,REV_START] "... [" addrs_str "]") 897 next 898} 899 900# close any previous srom revision descriptor 901$1 == ST_SROM_DEFN && in_state(ST_SROM_DEFN) { 902 pop_state() 903} 904 905# open a new srom revision descriptor 906$1 == ST_SROM_DEFN && allow_def(ST_SROM_DEFN) { 907 # parse revision descriptor 908 parse_revdesc(rev_desc) 909 910 # assign revision id 911 vid = g(STATE_IDENT) 912 rev = vars[vid,NUM_REVS] "" 913 revk = subkey(vid, REV, rev) 914 vars[vid,NUM_REVS]++ 915 916 # vend scoped rev/revk variables for use in the 917 # revision offset block 918 push("rev_id", rev) 919 push("rev_key", revk) 920 921 # init basic revision state 922 vars[revk,DEF_LINE] = NR 923 vars[revk,REV_START] = rev_desc[REV_START] 924 vars[revk,REV_END] = rev_desc[REV_END] 925 vars[revk,REV_NUM_OFFS] = 0 926 927 debug("srom " rev_desc[REV_START] "-" rev_desc[REV_END] " {") 928 push_state(ST_SROM_DEFN, null, 0) 929 930 # seek to the first offset definition 931 do { 932 shiftf(1) 933 } while ($1 !~ SROM_OFF_REGEX && NF > 0) 934} 935 936# 937# Extract and return the array length from the given type string. 938# Returns -1 if the type is not an array. 939# 940function type_array_len (type) 941{ 942 # extract byte count[] and width 943 if (match(type, ARRAY_REGEX"$") > 0) { 944 return (substr(type, RSTART+1, RLENGTH-2)) 945 } else { 946 return (-1) 947 } 948} 949 950# 951# Parse an offset declaration from the current line. 952# 953function parse_offset_segment (revk, offk) 954{ 955 vid = g(STATE_IDENT) 956 957 # use explicit type if specified, otherwise use the variable's 958 # common type 959 if ($1 !~ HEX_REGEX) { 960 type = $1 961 if (type !~ TYPES_REGEX) 962 error("unknown field type '" type "'") 963 964 shiftf(1) 965 } else { 966 type = vars[vid,VAR_TYPE] 967 } 968 969 # read offset value 970 offset = $1 971 if (offset !~ HEX_REGEX) 972 error("invalid offset value '" offset "'") 973 974 # extract byte count[], base type, and width 975 if (match(type, ARRAY_REGEX"$") > 0) { 976 count = int(substr(type, RSTART+1, RLENGTH-2)) 977 type = substr(type, 1, RSTART-1) 978 } else { 979 count = 1 980 } 981 width = TSIZE[type] 982 983 # seek to attributes or end of the offset expr 984 sub("^[^,(|){}]+", "", $0) 985 986 # parse attributes 987 mask=TMASK[type] 988 shift=0 989 990 if ($1 ~ "^\\(") { 991 # extract attribute list 992 if (match($0, "\\([^|\(\)]*\\)") <= 0) 993 error("expected attribute list") 994 attr_str = substr($0, RSTART+1, RLENGTH-2) 995 996 # drop from input line 997 $0 = substr($0, RSTART+RLENGTH, length($0) - RSTART+RLENGTH) 998 999 # parse attributes 1000 num_attr = split(attr_str, attrs, ",[ \t]*") 1001 for (i = 1; i <= num_attr; i++) { 1002 attr = attrs[i] 1003 if (sub("^&[ \t]*", "", attr) > 0) { 1004 mask = attr 1005 } else if (sub("^<<[ \t]*", "", attr) > 0) { 1006 shift = "-"attr 1007 } else if (sub("^>>[ \t]*", "", attr) > 0) { 1008 shift = attr 1009 } else { 1010 error("unknown attribute '" attr "'") 1011 } 1012 } 1013 } 1014 1015 # assign segment id 1016 seg = vars[offk,OFF_NUM_SEGS] "" 1017 segk = subkey(offk, OFF_SEG, seg) 1018 vars[offk,OFF_NUM_SEGS]++ 1019 1020 vars[segk,SEG_ADDR] = offset + (width * _oi) 1021 vars[segk,SEG_COUNT] = count 1022 vars[segk,SEG_TYPE] = type 1023 vars[segk,SEG_MASK] = mask 1024 vars[segk,SEG_SHIFT] = shift 1025 1026 debug("{"vars[segk,SEG_ADDR]", "type", "mask", "shift"}" \ 1027 _comma) 1028} 1029 1030# revision offset definition 1031$1 ~ SROM_OFF_REGEX && in_state(ST_SROM_DEFN) { 1032 vid = g(STATE_IDENT) 1033 1034 # fetch rev id/key defined by our parent block 1035 rev = g("rev_id") 1036 revk = g("rev_key") 1037 1038 # parse all offsets 1039 do { 1040 # assign offset id 1041 off = vars[revk,REV_NUM_OFFS] "" 1042 offk = subkey(revk, OFF, off) 1043 vars[revk,REV_NUM_OFFS]++ 1044 1045 # initialize segment count 1046 vars[offk,DEF_LINE] = NR 1047 vars[offk,OFF_NUM_SEGS] = 0 1048 1049 debug("[") 1050 # parse all segments 1051 do { 1052 parse_offset_segment(revk, offk) 1053 _more_seg = ($1 == "|") 1054 if (_more_seg) 1055 shiftf(1, 1) 1056 } while (_more_seg) 1057 debug("],") 1058 _more_vals = ($1 == ",") 1059 if (_more_vals) 1060 shiftf(1, 1) 1061 } while (_more_vals) 1062} 1063 1064# variable definition 1065(($1 == "private" && $2 ~ TYPES_REGEX) || $1 ~ TYPES_REGEX) && 1066 allow_def(ST_VAR_BLOCK) \ 1067{ 1068 # check for 'private' flag 1069 if ($1 == "private") { 1070 private = 1 1071 shiftf(1) 1072 } else { 1073 private = 0 1074 } 1075 1076 type = $1 1077 name = $2 1078 array = 0 1079 debug(type " " name " {") 1080 1081 # Check for and remove any array[] specifier 1082 base_type = type 1083 if (sub(ARRAY_REGEX"$", "", base_type) > 0) 1084 array = 1 1085 1086 # verify type 1087 if (!base_type in DTYPE) 1088 error("unknown type '" $1 "'") 1089 1090 # Add top-level variable entry 1091 if (name in var_names) 1092 error("variable identifier '" name "' previously defined on " \ 1093 "line " vars[name,DEF_LINE]) 1094 1095 var_names[name] = 0 1096 vars[name,VAR_NAME] = name 1097 vars[name,DEF_LINE] = NR 1098 vars[name,VAR_TYPE] = type 1099 vars[name,VAR_BASE_TYPE] = base_type 1100 vars[name,NUM_REVS] = 0 1101 vars[name,VAR_PRIVATE] = private 1102 vars[name,VAR_ARRAY] = array 1103 vars[name,VAR_FMT] = "hex" # default if not specified 1104 1105 open_block(ST_VAR_BLOCK, name) 1106 1107 debug("type=" DTYPE[base_type]) 1108 1109 if (in_nested_state(ST_STRUCT_BLOCK)) { 1110 # Fetch the enclosing struct's name 1111 sid = g(STATE_IDENT, 1) 1112 1113 # Mark as a struct-based variable 1114 vars[name,VAR_STRUCT] = sid 1115 } 1116} 1117 1118# variable parameters 1119$1 ~ IDENT_REGEX && $2 ~ IDENT_REGEX && in_state(ST_VAR_BLOCK) { 1120 vid = g(STATE_IDENT) 1121 if ($1 == PROP_T_SFMT) { 1122 if (!$2 in FMT) 1123 error("invalid fmt '" $2 "'") 1124 1125 vars[vid,VAR_FMT] = $2 1126 debug($1 "=" FMT[$2]) 1127 } else if ($1 == PROP_T_ALL1 && $2 == "ignore") { 1128 vars[vid,VAR_IGNALL1] = 1 1129 } else { 1130 error("unknown parameter " $1) 1131 } 1132 next 1133} 1134 1135# Skip comments and blank lines 1136/^[ \t]*#/ || /^$/ { 1137 next 1138} 1139 1140# Close blocks 1141/}/ && !in_state(ST_NONE) { 1142 while (!in_state(ST_NONE) && $0 ~ "}") { 1143 close_block(); 1144 debug("}") 1145 } 1146 next 1147} 1148 1149# Report unbalanced '}' 1150/}/ && in_state(ST_NONE) { 1151 error("extra '}'") 1152} 1153 1154# Invalid variable type 1155$1 && allow_def(ST_VAR_BLOCK) { 1156 error("unknown type '" $1 "'") 1157} 1158 1159# Generic parse failure 1160{ 1161 error("unrecognized statement") 1162} 1163