1e83ce340SAdrian Chadd#!/usr/bin/awk -f 2e83ce340SAdrian Chadd 3e83ce340SAdrian Chadd#- 4e83ce340SAdrian Chadd# Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 5e83ce340SAdrian Chadd# All rights reserved. 6e83ce340SAdrian Chadd# 7e83ce340SAdrian Chadd# Redistribution and use in source and binary forms, with or without 8e83ce340SAdrian Chadd# modification, are permitted provided that the following conditions 9e83ce340SAdrian Chadd# are met: 10e83ce340SAdrian Chadd# 1. Redistributions of source code must retain the above copyright 11e83ce340SAdrian Chadd# notice, this list of conditions and the following disclaimer, 12e83ce340SAdrian Chadd# without modification. 13e83ce340SAdrian Chadd# 2. Redistributions in binary form must reproduce at minimum a disclaimer 14e83ce340SAdrian Chadd# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15e83ce340SAdrian Chadd# redistribution must be conditioned upon including a substantially 16e83ce340SAdrian Chadd# similar Disclaimer requirement for further binary redistribution. 17e83ce340SAdrian Chadd# 18e83ce340SAdrian Chadd# NO WARRANTY 19e83ce340SAdrian Chadd# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20e83ce340SAdrian Chadd# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21e83ce340SAdrian Chadd# LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22e83ce340SAdrian Chadd# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23e83ce340SAdrian Chadd# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24e83ce340SAdrian Chadd# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25e83ce340SAdrian Chadd# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26e83ce340SAdrian Chadd# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27e83ce340SAdrian Chadd# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28e83ce340SAdrian Chadd# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29e83ce340SAdrian Chadd# THE POSSIBILITY OF SUCH DAMAGES. 30e83ce340SAdrian Chadd# 31e83ce340SAdrian Chadd 3277cb4d3eSLandon J. FullerBEGIN { main() } 3377cb4d3eSLandon J. FullerEND { at_exit() } 3477cb4d3eSLandon J. Fuller 3577cb4d3eSLandon J. Fuller# 3677cb4d3eSLandon J. Fuller# Print usage 3777cb4d3eSLandon J. Fuller# 3877cb4d3eSLandon J. Fullerfunction usage() { 3977cb4d3eSLandon J. Fuller print "usage: bhnd_nvram_map.awk <input map> [-hd] [-o output file]" 4077cb4d3eSLandon J. Fuller _EARLY_EXIT = 1 4177cb4d3eSLandon J. Fuller exit 1 4277cb4d3eSLandon J. Fuller} 4377cb4d3eSLandon J. Fuller 4477cb4d3eSLandon J. Fullerfunction main(_i) { 45e83ce340SAdrian Chadd RS="\n" 46e83ce340SAdrian Chadd 47e83ce340SAdrian Chadd OUTPUT_FILE = null 48e83ce340SAdrian Chadd 4977cb4d3eSLandon J. Fuller # Probe awk implementation's hex digit handling 5077cb4d3eSLandon J. Fuller if ("0xA" + 0 != 10) { 5177cb4d3eSLandon J. Fuller AWK_REQ_HEX_PARSING=1 5277cb4d3eSLandon J. Fuller } 5377cb4d3eSLandon J. Fuller 54e83ce340SAdrian Chadd # Output type 55e83ce340SAdrian Chadd OUT_T = null 56e83ce340SAdrian Chadd OUT_T_HEADER = "HEADER" 57e83ce340SAdrian Chadd OUT_T_DATA = "DATA" 58*4f4eb606SMatt Macy VERBOSE = 0 59e83ce340SAdrian Chadd 6077cb4d3eSLandon J. Fuller # Tab width to use when calculating output alignment 6177cb4d3eSLandon J. Fuller TAB_WIDTH = 8 6277cb4d3eSLandon J. Fuller 63e83ce340SAdrian Chadd # Enable debug output 64e83ce340SAdrian Chadd DEBUG = 0 65e83ce340SAdrian Chadd 66e83ce340SAdrian Chadd # Maximum revision 6777cb4d3eSLandon J. Fuller REV_MAX = 256 68e83ce340SAdrian Chadd 69e83ce340SAdrian Chadd # Parse arguments 70e83ce340SAdrian Chadd if (ARGC < 2) 71e83ce340SAdrian Chadd usage() 72e83ce340SAdrian Chadd 7377cb4d3eSLandon J. Fuller for (_i = 1; _i < ARGC; _i++) { 7477cb4d3eSLandon J. Fuller if (ARGV[_i] == "--debug") { 75e83ce340SAdrian Chadd DEBUG = 1 7677cb4d3eSLandon J. Fuller } else if (ARGV[_i] == "-d" && OUT_T == null) { 77e83ce340SAdrian Chadd OUT_T = OUT_T_DATA 7877cb4d3eSLandon J. Fuller } else if (ARGV[_i] == "-h" && OUT_T == null) { 79e83ce340SAdrian Chadd OUT_T = OUT_T_HEADER 80*4f4eb606SMatt Macy } else if (ARGV[_i] == "-v") { 81*4f4eb606SMatt Macy VERBOSE = 1 8277cb4d3eSLandon J. Fuller } else if (ARGV[_i] == "-o") { 8377cb4d3eSLandon J. Fuller _i++ 8477cb4d3eSLandon J. Fuller if (_i >= ARGC) 85e83ce340SAdrian Chadd usage() 86e83ce340SAdrian Chadd 8777cb4d3eSLandon J. Fuller OUTPUT_FILE = ARGV[_i] 8877cb4d3eSLandon J. Fuller } else if (ARGV[_i] == "--") { 8977cb4d3eSLandon J. Fuller _i++ 90e83ce340SAdrian Chadd break 9177cb4d3eSLandon J. Fuller } else if (ARGV[_i] !~ /^-/) { 9277cb4d3eSLandon J. Fuller FILENAME = ARGV[_i] 93e83ce340SAdrian Chadd } else { 9477cb4d3eSLandon J. Fuller print "unknown option " ARGV[_i] 95e83ce340SAdrian Chadd usage() 96e83ce340SAdrian Chadd } 97e83ce340SAdrian Chadd } 98e83ce340SAdrian Chadd 99e83ce340SAdrian Chadd ARGC=2 100e83ce340SAdrian Chadd 101e83ce340SAdrian Chadd if (OUT_T == null) { 102e83ce340SAdrian Chadd print("error: one of -d or -h required") 103e83ce340SAdrian Chadd usage() 104e83ce340SAdrian Chadd } 105e83ce340SAdrian Chadd 106e83ce340SAdrian Chadd if (FILENAME == null) { 107e83ce340SAdrian Chadd print("error: no input file specified") 108e83ce340SAdrian Chadd usage() 109e83ce340SAdrian Chadd } 110e83ce340SAdrian Chadd 111e83ce340SAdrian Chadd if (OUTPUT_FILE == "-") { 112e83ce340SAdrian Chadd OUTPUT_FILE = "/dev/stdout" 113e83ce340SAdrian Chadd } else if (OUTPUT_FILE == null) { 11477cb4d3eSLandon J. Fuller OUTPUT_FILE_IDX = split(FILENAME, _g_output_path, "/") 11577cb4d3eSLandon J. Fuller OUTPUT_FILE = _g_output_path[OUTPUT_FILE_IDX] 116e83ce340SAdrian Chadd 117e83ce340SAdrian Chadd if (OUTPUT_FILE !~ /^bhnd_/) 118e83ce340SAdrian Chadd OUTPUT_FILE = "bhnd_" OUTPUT_FILE 119e83ce340SAdrian Chadd 120e83ce340SAdrian Chadd if (OUT_T == OUT_T_HEADER) 121e83ce340SAdrian Chadd OUTPUT_FILE = OUTPUT_FILE ".h" 122e83ce340SAdrian Chadd else 123e83ce340SAdrian Chadd OUTPUT_FILE = OUTPUT_FILE "_data.h" 124e83ce340SAdrian Chadd } 125e83ce340SAdrian Chadd 126e83ce340SAdrian Chadd # Common Regexs 12777cb4d3eSLandon J. Fuller UINT_REGEX = "^(0|[1-9][0-9]*)$" 12877cb4d3eSLandon J. Fuller HEX_REGEX = "^(0x[A-Fa-f0-9]+)$" 12977cb4d3eSLandon J. Fuller OFF_REGEX = "^(0|[1-9][0-9]*)|^(0x[A-Fa-f0-9]+)" 13077cb4d3eSLandon J. Fuller REL_OFF_REGEX = "^\\+(0|[1-9][0-9]*)|^\\+(0x[A-Fa-f0-9]+)" 131e83ce340SAdrian Chadd 132e83ce340SAdrian Chadd ARRAY_REGEX = "\\[(0|[1-9][0-9]*)\\]" 13377cb4d3eSLandon J. Fuller TYPES_REGEX = "^(((u|i)(8|16|32))|char)("ARRAY_REGEX")?$" 134e83ce340SAdrian Chadd 13577cb4d3eSLandon J. Fuller IDENT_REGEX = "[A-Za-z_][A-Za-z0-9_]*" 13677cb4d3eSLandon J. Fuller SVAR_IDENT_REGEX = "^<"IDENT_REGEX">{?$" # <var> identifiers 13777cb4d3eSLandon J. Fuller VAR_IDENT_REGEX = "^"IDENT_REGEX"{?$" # var identifiers 138e83ce340SAdrian Chadd 13977cb4d3eSLandon J. Fuller VACCESS_REGEX = "^(private|internal)$" 140e83ce340SAdrian Chadd 14177cb4d3eSLandon J. Fuller # Property array keys 14277cb4d3eSLandon J. Fuller PROP_ID = "p_id" 14377cb4d3eSLandon J. Fuller PROP_NAME = "p_name" 144e83ce340SAdrian Chadd 14577cb4d3eSLandon J. Fuller # Prop path array keys 14677cb4d3eSLandon J. Fuller PPATH_HEAD = "ppath_head" 14777cb4d3eSLandon J. Fuller PPATH_TAIL = "ppath_tail" 148e83ce340SAdrian Chadd 14977cb4d3eSLandon J. Fuller # Object array keys 15077cb4d3eSLandon J. Fuller OBJ_IS_CLS = "o_is_cls" 15177cb4d3eSLandon J. Fuller OBJ_SUPER = "o_super" 15277cb4d3eSLandon J. Fuller OBJ_PROP = "o_prop" 153e83ce340SAdrian Chadd 15477cb4d3eSLandon J. Fuller # Class array keys 15577cb4d3eSLandon J. Fuller CLS_NAME = "cls_name" 15677cb4d3eSLandon J. Fuller CLS_PROP = "cls_prop" 157e83ce340SAdrian Chadd 15877cb4d3eSLandon J. Fuller # C SPROM binding opcodes/opcode flags 15977cb4d3eSLandon J. Fuller SPROM_OPCODE_EOF = "SPROM_OPCODE_EOF" 16077cb4d3eSLandon J. Fuller SPROM_OPCODE_NELEM = "SPROM_OPCODE_NELEM" 16177cb4d3eSLandon J. Fuller SPROM_OPCODE_VAR_END = "SPROM_OPCODE_VAR_END" 16277cb4d3eSLandon J. Fuller SPROM_OPCODE_VAR_IMM = "SPROM_OPCODE_VAR_IMM" 16377cb4d3eSLandon J. Fuller SPROM_OPCODE_VAR_REL_IMM = "SPROM_OPCODE_VAR_REL_IMM" 16477cb4d3eSLandon J. Fuller SPROM_OPCODE_VAR = "SPROM_OPCODE_VAR" 16577cb4d3eSLandon J. Fuller SPROM_OPCODE_REV_IMM = "SPROM_OPCODE_REV_IMM" 16677cb4d3eSLandon J. Fuller SPROM_OPCODE_REV_RANGE = "SPROM_OPCODE_REV_RANGE" 16777cb4d3eSLandon J. Fuller SPROM_OP_REV_START_MASK = "SPROM_OP_REV_START_MASK" 16877cb4d3eSLandon J. Fuller SPROM_OP_REV_START_SHIFT = "SPROM_OP_REV_START_SHIFT" 16977cb4d3eSLandon J. Fuller SPROM_OP_REV_END_MASK = "SPROM_OP_REV_END_MASK" 17077cb4d3eSLandon J. Fuller SPROM_OP_REV_END_SHIFT = "SPROM_OP_REV_END_SHIFT" 17177cb4d3eSLandon J. Fuller SPROM_OPCODE_MASK_IMM = "SPROM_OPCODE_MASK_IMM" 17277cb4d3eSLandon J. Fuller SPROM_OPCODE_MASK = "SPROM_OPCODE_MASK" 17377cb4d3eSLandon J. Fuller SPROM_OPCODE_SHIFT_IMM = "SPROM_OPCODE_SHIFT_IMM" 17477cb4d3eSLandon J. Fuller SPROM_OPCODE_SHIFT = "SPROM_OPCODE_SHIFT" 17577cb4d3eSLandon J. Fuller SPROM_OPCODE_OFFSET_REL_IMM = "SPROM_OPCODE_OFFSET_REL_IMM" 17677cb4d3eSLandon J. Fuller SPROM_OPCODE_OFFSET = "SPROM_OPCODE_OFFSET" 17777cb4d3eSLandon J. Fuller SPROM_OPCODE_TYPE = "SPROM_OPCODE_TYPE" 17877cb4d3eSLandon J. Fuller SPROM_OPCODE_TYPE_IMM = "SPROM_OPCODE_TYPE_IMM" 17977cb4d3eSLandon J. Fuller SPROM_OPCODE_DO_BINDN_IMM = "SPROM_OPCODE_DO_BINDN_IMM" 18077cb4d3eSLandon J. Fuller SPROM_OPCODE_DO_BIND = "SPROM_OPCODE_DO_BIND" 18177cb4d3eSLandon J. Fuller SPROM_OPCODE_DO_BINDN = "SPROM_OPCODE_DO_BINDN" 18277cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_IN_MASK = "SPROM_OP_BIND_SKIP_IN_MASK" 18377cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_IN_SHIFT = "SPROM_OP_BIND_SKIP_IN_SHIFT" 18477cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_IN_SIGN = "SPROM_OP_BIND_SKIP_IN_SIGN" 18577cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_OUT_MASK = "SPROM_OP_BIND_SKIP_OUT_MASK" 18677cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_OUT_SHIFT = "SPROM_OP_BIND_SKIP_OUT_SHIFT" 187e83ce340SAdrian Chadd 18877cb4d3eSLandon J. Fuller SPROM_OP_DATA_U8 = "SPROM_OP_DATA_U8" 18977cb4d3eSLandon J. Fuller SPROM_OP_DATA_U8_SCALED = "SPROM_OP_DATA_U8_SCALED" 19077cb4d3eSLandon J. Fuller SPROM_OP_DATA_U16 = "SPROM_OP_DATA_U16" 19177cb4d3eSLandon J. Fuller SPROM_OP_DATA_U32 = "SPROM_OP_DATA_U32" 19277cb4d3eSLandon J. Fuller SPROM_OP_DATA_I8 = "SPROM_OP_DATA_I8" 193e83ce340SAdrian Chadd 19477cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_IN_MAX = 3 # maximum SKIP_IN value 19577cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_IN_MIN = -3 # minimum SKIP_IN value 19677cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_OUT_MAX = 1 # maximum SKIP_OUT value 19777cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_OUT_MIN = 0 # minimum SKIP_OUT value 19877cb4d3eSLandon J. Fuller SPROM_OP_IMM_MAX = 15 # maximum immediate value 19977cb4d3eSLandon J. Fuller SPROM_OP_REV_RANGE_MAX = 15 # maximum SROM rev range value 20077cb4d3eSLandon J. Fuller 20177cb4d3eSLandon J. Fuller # SPROM opcode encoding state 20277cb4d3eSLandon J. Fuller SromOpStream = class_new("SromOpStream") 20377cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_layout, "layout") 20477cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_revisions, "revisions") 20577cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_vid, "vid") 20677cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_offset, "offset") 20777cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_type, "type") 20877cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_nelem, "nelem") 20977cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_mask, "mask") 21077cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_shift, "shift") 21177cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_bind_total, "bind_total") 21277cb4d3eSLandon J. Fuller class_add_prop(SromOpStream, p_pending_bind, "pending_bind") 21377cb4d3eSLandon J. Fuller 21477cb4d3eSLandon J. Fuller # SROM pending bind operation 21577cb4d3eSLandon J. Fuller SromOpBind = class_new("SromOpBind") 21677cb4d3eSLandon J. Fuller class_add_prop(SromOpBind, p_segment, "segment") 21777cb4d3eSLandon J. Fuller class_add_prop(SromOpBind, p_count, "count") 21877cb4d3eSLandon J. Fuller class_add_prop(SromOpBind, p_offset, "offset") 21977cb4d3eSLandon J. Fuller class_add_prop(SromOpBind, p_width, "width") 22077cb4d3eSLandon J. Fuller class_add_prop(SromOpBind, p_skip_in, "skip_in") 22177cb4d3eSLandon J. Fuller class_add_prop(SromOpBind, p_skip_out, "skip_out") 22277cb4d3eSLandon J. Fuller class_add_prop(SromOpBind, p_buffer, "buffer") 22377cb4d3eSLandon J. Fuller 22477cb4d3eSLandon J. Fuller # Map class definition 22577cb4d3eSLandon J. Fuller Map = class_new("Map") 22677cb4d3eSLandon J. Fuller 22777cb4d3eSLandon J. Fuller # Array class definition 22877cb4d3eSLandon J. Fuller Array = class_new("Array") 22977cb4d3eSLandon J. Fuller class_add_prop(Array, p_count, "count") 23077cb4d3eSLandon J. Fuller 23177cb4d3eSLandon J. Fuller # MacroType class definition 23277cb4d3eSLandon J. Fuller # Used to define a set of known macro types that may be generated 23377cb4d3eSLandon J. Fuller MacroType = class_new("MacroType") 23477cb4d3eSLandon J. Fuller class_add_prop(MacroType, p_name, "name") 23577cb4d3eSLandon J. Fuller class_add_prop(MacroType, p_const_suffix, "const_suffix") 23677cb4d3eSLandon J. Fuller 23777cb4d3eSLandon J. Fuller MTypeVarName = macro_type_new("name", "") # var name 23877cb4d3eSLandon J. Fuller MTypeVarID = macro_type_new("id", "_ID") # var unique ID 23977cb4d3eSLandon J. Fuller MTypeVarMaxLen = macro_type_new("len", "_MAXLEN") # var max array length 24077cb4d3eSLandon J. Fuller 24177cb4d3eSLandon J. Fuller # Preprocessor Constant 24277cb4d3eSLandon J. Fuller MacroDefine = class_new("MacroDefine") 24377cb4d3eSLandon J. Fuller class_add_prop(MacroDefine, p_name, "name") 24477cb4d3eSLandon J. Fuller class_add_prop(MacroDefine, p_value, "value") 24577cb4d3eSLandon J. Fuller 24677cb4d3eSLandon J. Fuller # ParseState definition 24777cb4d3eSLandon J. Fuller ParseState = class_new("ParseState") 24877cb4d3eSLandon J. Fuller class_add_prop(ParseState, p_ctx, "ctx") 24977cb4d3eSLandon J. Fuller class_add_prop(ParseState, p_is_block, "is_block") 25077cb4d3eSLandon J. Fuller class_add_prop(ParseState, p_line, "line") 25177cb4d3eSLandon J. Fuller 25277cb4d3eSLandon J. Fuller # Value Formats 25377cb4d3eSLandon J. Fuller Fmt = class_new("Fmt") 25477cb4d3eSLandon J. Fuller class_add_prop(Fmt, p_name, "name") 255c283839dSLandon J. Fuller class_add_prop(Fmt, p_symbol, "symbol") 256c283839dSLandon J. Fuller class_add_prop(Fmt, p_array_fmt, "array_fmt") 25777cb4d3eSLandon J. Fuller 25877cb4d3eSLandon J. Fuller FmtHex = fmt_new("hex", "bhnd_nvram_val_bcm_hex_fmt") 25977cb4d3eSLandon J. Fuller FmtDec = fmt_new("decimal", "bhnd_nvram_val_bcm_decimal_fmt") 26077cb4d3eSLandon J. Fuller FmtMAC = fmt_new("macaddr", "bhnd_nvram_val_bcm_macaddr_fmt") 26177cb4d3eSLandon J. Fuller FmtLEDDC = fmt_new("leddc", "bhnd_nvram_val_bcm_leddc_fmt") 262c283839dSLandon J. Fuller FmtCharArray = fmt_new("char_array", "bhnd_nvram_val_char_array_fmt") 263c283839dSLandon J. Fuller FmtChar = fmt_new("char", "bhnd_nvram_val_char_array_fmt", 264c283839dSLandon J. Fuller FmtCharArray) 26577cb4d3eSLandon J. Fuller FmtStr = fmt_new("string", "bhnd_nvram_val_bcm_string_fmt") 26677cb4d3eSLandon J. Fuller 267c283839dSLandon J. Fuller # User-specifiable value formats 26877cb4d3eSLandon J. Fuller ValueFormats = map_new() 26977cb4d3eSLandon J. Fuller map_set(ValueFormats, get(FmtHex, p_name), FmtHex) 27077cb4d3eSLandon J. Fuller map_set(ValueFormats, get(FmtDec, p_name), FmtDec) 27177cb4d3eSLandon J. Fuller map_set(ValueFormats, get(FmtMAC, p_name), FmtMAC) 27277cb4d3eSLandon J. Fuller map_set(ValueFormats, get(FmtLEDDC, p_name), FmtLEDDC) 27377cb4d3eSLandon J. Fuller map_set(ValueFormats, get(FmtStr, p_name), FmtStr) 27477cb4d3eSLandon J. Fuller 27577cb4d3eSLandon J. Fuller # Data Types 27677cb4d3eSLandon J. Fuller Type = class_new("Type") 27777cb4d3eSLandon J. Fuller class_add_prop(Type, p_name, "name") 27877cb4d3eSLandon J. Fuller class_add_prop(Type, p_width, "width") 27977cb4d3eSLandon J. Fuller class_add_prop(Type, p_signed, "signed") 28077cb4d3eSLandon J. Fuller class_add_prop(Type, p_const, "const") 28177cb4d3eSLandon J. Fuller class_add_prop(Type, p_const_val, "const_val") 28277cb4d3eSLandon J. Fuller class_add_prop(Type, p_array_const, "array_const") 28377cb4d3eSLandon J. Fuller class_add_prop(Type, p_array_const_val, "array_const_val") 28477cb4d3eSLandon J. Fuller class_add_prop(Type, p_default_fmt, "default_fmt") 28577cb4d3eSLandon J. Fuller class_add_prop(Type, p_mask, "mask") 28677cb4d3eSLandon J. Fuller 28777cb4d3eSLandon J. Fuller ArrayType = class_new("ArrayType", AST) 28877cb4d3eSLandon J. Fuller class_add_prop(ArrayType, p_type, "type") 28977cb4d3eSLandon J. Fuller class_add_prop(ArrayType, p_count, "count") 29077cb4d3eSLandon J. Fuller 29177cb4d3eSLandon J. Fuller UInt8Max = 255 29277cb4d3eSLandon J. Fuller UInt16Max = 65535 29377cb4d3eSLandon J. Fuller UInt32Max = 4294967295 29477cb4d3eSLandon J. Fuller Int8Min = -128 29577cb4d3eSLandon J. Fuller Int8Max = 127 29677cb4d3eSLandon J. Fuller Int16Min = -32768 29777cb4d3eSLandon J. Fuller Int16Max = 32767 29877cb4d3eSLandon J. Fuller Int32Min = -2147483648 29977cb4d3eSLandon J. Fuller Int32Max = 2147483648 30077cb4d3eSLandon J. Fuller CharMin = Int8Min 30177cb4d3eSLandon J. Fuller CharMax = Int8Max 30277cb4d3eSLandon J. Fuller 30377cb4d3eSLandon J. Fuller UInt8 = type_new("u8", 1, 0, "BHND_NVRAM_TYPE_UINT8", 30477cb4d3eSLandon J. Fuller "BHND_NVRAM_TYPE_UINT8_ARRAY", FmtHex, UInt8Max, 0, 16) 30577cb4d3eSLandon J. Fuller 30677cb4d3eSLandon J. Fuller UInt16 = type_new("u16", 2, 0, "BHND_NVRAM_TYPE_UINT16", 30777cb4d3eSLandon J. Fuller "BHND_NVRAM_TYPE_UINT16_ARRAY", FmtHex, UInt16Max, 1, 17) 30877cb4d3eSLandon J. Fuller 30977cb4d3eSLandon J. Fuller UInt32 = type_new("u32", 4, 0, "BHND_NVRAM_TYPE_UINT32", 31077cb4d3eSLandon J. Fuller "BHND_NVRAM_TYPE_UINT32_ARRAY", FmtHex, UInt32Max, 2, 18) 31177cb4d3eSLandon J. Fuller 31277cb4d3eSLandon J. Fuller Int8 = type_new("i8", 1, 1, "BHND_NVRAM_TYPE_INT8", 31377cb4d3eSLandon J. Fuller "BHND_NVRAM_TYPE_INT8_ARRAY", FmtDec, UInt8Max, 4, 20) 31477cb4d3eSLandon J. Fuller 31577cb4d3eSLandon J. Fuller Int16 = type_new("i16", 2, 1, "BHND_NVRAM_TYPE_INT16", 31677cb4d3eSLandon J. Fuller "BHND_NVRAM_TYPE_INT16_ARRAY", FmtDec, UInt16Max, 5, 21) 31777cb4d3eSLandon J. Fuller 31877cb4d3eSLandon J. Fuller Int32 = type_new("i32", 4, 1, "BHND_NVRAM_TYPE_INT32", 31977cb4d3eSLandon J. Fuller "BHND_NVRAM_TYPE_INT32_ARRAY", FmtDec, UInt32Max, 6, 22) 32077cb4d3eSLandon J. Fuller 32177cb4d3eSLandon J. Fuller Char = type_new("char", 1, 1, "BHND_NVRAM_TYPE_CHAR", 322c283839dSLandon J. Fuller "BHND_NVRAM_TYPE_CHAR_ARRAY", FmtChar, UInt8Max, 8, 24) 32377cb4d3eSLandon J. Fuller 32477cb4d3eSLandon J. Fuller BaseTypes = map_new() 32577cb4d3eSLandon J. Fuller map_set(BaseTypes, get(UInt8, p_name), UInt8) 32677cb4d3eSLandon J. Fuller map_set(BaseTypes, get(UInt16, p_name), UInt16) 32777cb4d3eSLandon J. Fuller map_set(BaseTypes, get(UInt32, p_name), UInt32) 32877cb4d3eSLandon J. Fuller map_set(BaseTypes, get(Int8, p_name), Int8) 32977cb4d3eSLandon J. Fuller map_set(BaseTypes, get(Int16, p_name), Int16) 33077cb4d3eSLandon J. Fuller map_set(BaseTypes, get(Int32, p_name), Int32) 33177cb4d3eSLandon J. Fuller map_set(BaseTypes, get(Char, p_name), Char) 33277cb4d3eSLandon J. Fuller 33377cb4d3eSLandon J. Fuller BaseTypesArray = map_to_array(BaseTypes) 33477cb4d3eSLandon J. Fuller BaseTypesCount = array_size(BaseTypesArray) 33577cb4d3eSLandon J. Fuller 33677cb4d3eSLandon J. Fuller # Variable Flags 33777cb4d3eSLandon J. Fuller VFlag = class_new("VFlag") 33877cb4d3eSLandon J. Fuller class_add_prop(VFlag, p_name, "name") 33977cb4d3eSLandon J. Fuller class_add_prop(VFlag, p_const, "const") 34077cb4d3eSLandon J. Fuller 34177cb4d3eSLandon J. Fuller VFlagPrivate = vflag_new("private", "BHND_NVRAM_VF_MFGINT") 34277cb4d3eSLandon J. Fuller VFlagIgnoreAll1 = vflag_new("ignall1", "BHND_NVRAM_VF_IGNALL1") 34377cb4d3eSLandon J. Fuller 34477cb4d3eSLandon J. Fuller # Variable Access Type Constants 34577cb4d3eSLandon J. Fuller VAccess = class_new("VAccess") 34677cb4d3eSLandon J. Fuller VAccessPublic = obj_new(VAccess) # Public 34777cb4d3eSLandon J. Fuller VAccessPrivate = obj_new(VAccess) # MFG Private 34877cb4d3eSLandon J. Fuller VAccessInternal = obj_new(VAccess) # Implementation-Internal 34977cb4d3eSLandon J. Fuller 35077cb4d3eSLandon J. Fuller # 35177cb4d3eSLandon J. Fuller # AST node classes 35277cb4d3eSLandon J. Fuller # 35377cb4d3eSLandon J. Fuller AST = class_new("AST") 35477cb4d3eSLandon J. Fuller class_add_prop(AST, p_line, "line") 35577cb4d3eSLandon J. Fuller 35677cb4d3eSLandon J. Fuller SymbolContext = class_new("SymbolContext", AST) 35777cb4d3eSLandon J. Fuller class_add_prop(SymbolContext, p_vars, "vars") 35877cb4d3eSLandon J. Fuller 35977cb4d3eSLandon J. Fuller # NVRAM root parser context 36077cb4d3eSLandon J. Fuller NVRAM = class_new("NVRAM", SymbolContext) 36177cb4d3eSLandon J. Fuller class_add_prop(NVRAM, p_var_groups, "var_groups") 36277cb4d3eSLandon J. Fuller class_add_prop(NVRAM, p_srom_layouts, "srom_layouts") 36377cb4d3eSLandon J. Fuller class_add_prop(NVRAM, p_srom_table, "srom_table") 36477cb4d3eSLandon J. Fuller 36577cb4d3eSLandon J. Fuller # Variable Group 36677cb4d3eSLandon J. Fuller VarGroup = class_new("VarGroup", SymbolContext) 36777cb4d3eSLandon J. Fuller class_add_prop(VarGroup, p_name, "name") 36877cb4d3eSLandon J. Fuller 36977cb4d3eSLandon J. Fuller # Revision Range 37077cb4d3eSLandon J. Fuller RevRange = class_new("RevRange", AST) 37177cb4d3eSLandon J. Fuller class_add_prop(RevRange, p_start, "start") 37277cb4d3eSLandon J. Fuller class_add_prop(RevRange, p_end, "end") 37377cb4d3eSLandon J. Fuller 37477cb4d3eSLandon J. Fuller # String Constant 37577cb4d3eSLandon J. Fuller StringConstant = class_new("StringConstant", AST) 37677cb4d3eSLandon J. Fuller class_add_prop(StringConstant, p_value, "value") # string 37777cb4d3eSLandon J. Fuller class_add_prop(StringConstant, p_continued, "continued") # bool 37877cb4d3eSLandon J. Fuller 37977cb4d3eSLandon J. Fuller # Variable Declaration 38077cb4d3eSLandon J. Fuller Var = class_new("Var", AST) 38177cb4d3eSLandon J. Fuller class_add_prop(Var, p_access, "access") # VAccess 38277cb4d3eSLandon J. Fuller class_add_prop(Var, p_name, "name") # string 38377cb4d3eSLandon J. Fuller class_add_prop(Var, p_desc, "desc") # StringConstant 38477cb4d3eSLandon J. Fuller class_add_prop(Var, p_help, "help") # StringConstant 38577cb4d3eSLandon J. Fuller class_add_prop(Var, p_type, "type") # AbstractType 38677cb4d3eSLandon J. Fuller class_add_prop(Var, p_fmt, "fmt") # Fmt 38777cb4d3eSLandon J. Fuller class_add_prop(Var, p_ignall1, "ignall1") # bool 38877cb4d3eSLandon J. Fuller # ID is assigned once all variables are sorted 38977cb4d3eSLandon J. Fuller class_add_prop(Var, p_vid, "vid") # int 39077cb4d3eSLandon J. Fuller 39177cb4d3eSLandon J. Fuller # Common interface inherited by parser contexts that support 39277cb4d3eSLandon J. Fuller # registration of SROM variable entries 39377cb4d3eSLandon J. Fuller SromContext = class_new("SromContext", AST) 39477cb4d3eSLandon J. Fuller class_add_prop(SromContext, p_revisions, "revisions") 39577cb4d3eSLandon J. Fuller 39677cb4d3eSLandon J. Fuller # SROM Layout Node 39777cb4d3eSLandon J. Fuller SromLayout = class_new("SromLayout", SromContext) 39877cb4d3eSLandon J. Fuller class_add_prop(SromLayout, p_entries, "entries") # Array<SromEntry> 39977cb4d3eSLandon J. Fuller class_add_prop(SromLayout, p_revmap, "revmap") # Map<(string,int), SromEntry> 40077cb4d3eSLandon J. Fuller class_add_prop(SromLayout, p_output_var_counts, # Map<int, int> (rev->count) 40177cb4d3eSLandon J. Fuller "output_var_counts") 40277cb4d3eSLandon J. Fuller 40377cb4d3eSLandon J. Fuller # SROM Layout Filter Node 40477cb4d3eSLandon J. Fuller # Represents a filter over a parent SromLayout's revisions 40577cb4d3eSLandon J. Fuller SromLayoutFilter = class_new("SromLayoutFilter", SromContext) 40677cb4d3eSLandon J. Fuller class_add_prop(SromLayoutFilter, p_parent, "parent") 40777cb4d3eSLandon J. Fuller 40877cb4d3eSLandon J. Fuller # SROM variable entry 40977cb4d3eSLandon J. Fuller SromEntry = class_new("SromEntry", AST) 41077cb4d3eSLandon J. Fuller class_add_prop(SromEntry, p_var, "var") 41177cb4d3eSLandon J. Fuller class_add_prop(SromEntry, p_revisions, "revisions") 41277cb4d3eSLandon J. Fuller class_add_prop(SromEntry, p_base_offset, "base_offset") 41377cb4d3eSLandon J. Fuller class_add_prop(SromEntry, p_type, "type") 41477cb4d3eSLandon J. Fuller class_add_prop(SromEntry, p_offsets, "offsets") 41577cb4d3eSLandon J. Fuller 41677cb4d3eSLandon J. Fuller # SROM variable offset 41777cb4d3eSLandon J. Fuller SromOffset = class_new("SromOffset", AST) 41877cb4d3eSLandon J. Fuller class_add_prop(SromOffset, p_segments, "segments") 41977cb4d3eSLandon J. Fuller 42077cb4d3eSLandon J. Fuller # SROM variable offset segment 42177cb4d3eSLandon J. Fuller SromSegment = class_new("SromSegment", AST) 42277cb4d3eSLandon J. Fuller class_add_prop(SromSegment, p_offset, "offset") 42377cb4d3eSLandon J. Fuller class_add_prop(SromSegment, p_type, "type") 42477cb4d3eSLandon J. Fuller class_add_prop(SromSegment, p_mask, "mask") 42577cb4d3eSLandon J. Fuller class_add_prop(SromSegment, p_shift, "shift") 42677cb4d3eSLandon J. Fuller class_add_prop(SromSegment, p_value, "value") 42777cb4d3eSLandon J. Fuller 42877cb4d3eSLandon J. Fuller # Create the parse state stack 42977cb4d3eSLandon J. Fuller _g_parse_stack_depth = 0 43077cb4d3eSLandon J. Fuller _g_parse_stack[0] = null 43177cb4d3eSLandon J. Fuller 43277cb4d3eSLandon J. Fuller # Push the root parse state 43377cb4d3eSLandon J. Fuller parser_state_push(nvram_new(), 0) 434e83ce340SAdrian Chadd} 435e83ce340SAdrian Chadd 43677cb4d3eSLandon J. Fullerfunction at_exit(_block_start, _state, _output_vars, _noutput_vars, _name, _var, 43777cb4d3eSLandon J. Fuller _i) 438e83ce340SAdrian Chadd{ 439e83ce340SAdrian Chadd # Skip completion handling if exiting from an error 440e83ce340SAdrian Chadd if (_EARLY_EXIT) 441e83ce340SAdrian Chadd exit 1 442e83ce340SAdrian Chadd 443e83ce340SAdrian Chadd # Check for complete block closure 44477cb4d3eSLandon J. Fuller if (!in_parser_context(NVRAM)) { 44577cb4d3eSLandon J. Fuller _state = parser_state_get() 44677cb4d3eSLandon J. Fuller _block_start = get(_state, p_line) 44777cb4d3eSLandon J. Fuller errorx("missing '}' for block opened on line " _block_start "") 448e83ce340SAdrian Chadd } 449e83ce340SAdrian Chadd 45077cb4d3eSLandon J. Fuller # Apply lexicographical sorting to our variable names. To support more 45177cb4d3eSLandon J. Fuller # effecient table searching, we guarantee a stable sort order (using C 45277cb4d3eSLandon J. Fuller # collation). 45377cb4d3eSLandon J. Fuller # 45477cb4d3eSLandon J. Fuller # This also has a side-effect of generating a unique monotonic ID 45577cb4d3eSLandon J. Fuller # for all variables, which we will emit as a #define and can use as a 45677cb4d3eSLandon J. Fuller # direct index into the C variable table 45777cb4d3eSLandon J. Fuller _output_vars = array_new() 45877cb4d3eSLandon J. Fuller for (_name in _g_var_names) { 45977cb4d3eSLandon J. Fuller _var = _g_var_names[_name] 46077cb4d3eSLandon J. Fuller 46177cb4d3eSLandon J. Fuller # Don't include internal variables in the output 46277cb4d3eSLandon J. Fuller if (var_is_internal(_var)) 46377cb4d3eSLandon J. Fuller continue 46477cb4d3eSLandon J. Fuller 46577cb4d3eSLandon J. Fuller array_append(_output_vars, _var) 466e83ce340SAdrian Chadd } 467e83ce340SAdrian Chadd 46877cb4d3eSLandon J. Fuller # Sort by variable name 46977cb4d3eSLandon J. Fuller array_sort(_output_vars, prop_to_path(p_name)) 47077cb4d3eSLandon J. Fuller 47177cb4d3eSLandon J. Fuller # Set all variable ID properties to their newly assigned ID value 47277cb4d3eSLandon J. Fuller _noutput_vars = array_size(_output_vars) 47377cb4d3eSLandon J. Fuller for (_i = 0; _i < _noutput_vars; _i++) { 47477cb4d3eSLandon J. Fuller _var = array_get(_output_vars, _i) 47577cb4d3eSLandon J. Fuller set(_var, p_vid, _i) 47677cb4d3eSLandon J. Fuller } 477e83ce340SAdrian Chadd 478e83ce340SAdrian Chadd # Truncate output file and write common header 479e83ce340SAdrian Chadd printf("") > OUTPUT_FILE 480e83ce340SAdrian Chadd emit("/*\n") 481e83ce340SAdrian Chadd emit(" * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.\n") 482e83ce340SAdrian Chadd emit(" *\n") 483e83ce340SAdrian Chadd emit(" * generated from nvram map: " FILENAME "\n") 484e83ce340SAdrian Chadd emit(" */\n") 485e83ce340SAdrian Chadd emit("\n") 486e83ce340SAdrian Chadd 487e83ce340SAdrian Chadd # Emit all variable definitions 488e83ce340SAdrian Chadd if (OUT_T == OUT_T_DATA) { 48977cb4d3eSLandon J. Fuller write_data(_output_vars) 490e83ce340SAdrian Chadd } else if (OUT_T == OUT_T_HEADER) { 49177cb4d3eSLandon J. Fuller write_header(_output_vars) 492e83ce340SAdrian Chadd } 493*4f4eb606SMatt Macy if (VERBOSE == 1) { 49477cb4d3eSLandon J. Fuller printf("%u variable records written to %s\n", array_size(_output_vars), 495e83ce340SAdrian Chadd OUTPUT_FILE) >> "/dev/stderr" 496e83ce340SAdrian Chadd } 497*4f4eb606SMatt Macy} 498e83ce340SAdrian Chadd 49977cb4d3eSLandon J. Fuller# Write the public header (output type HEADER) 50077cb4d3eSLandon J. Fullerfunction write_header(output_vars, _noutput_vars, _var, 50177cb4d3eSLandon J. Fuller _tab_align, _macro, _macros, _num_macros, _i) 502e83ce340SAdrian Chadd{ 50377cb4d3eSLandon J. Fuller # Produce our array of #defines 50477cb4d3eSLandon J. Fuller _num_macros = 0 50577cb4d3eSLandon J. Fuller _noutput_vars = array_size(output_vars) 50677cb4d3eSLandon J. Fuller for (_i = 0; _i < _noutput_vars; _i++) { 50777cb4d3eSLandon J. Fuller _var = array_get(output_vars, _i) 50877cb4d3eSLandon J. Fuller 50977cb4d3eSLandon J. Fuller # Variable name 51077cb4d3eSLandon J. Fuller _macro = var_get_macro(_var, MTypeVarName, \ 51177cb4d3eSLandon J. Fuller "\"" get(_var, p_name) "\"") 51277cb4d3eSLandon J. Fuller _macros[_num_macros++] = _macro 51377cb4d3eSLandon J. Fuller 51477cb4d3eSLandon J. Fuller # Variable array length 51577cb4d3eSLandon J. Fuller if (var_has_array_type(_var)) { 51677cb4d3eSLandon J. Fuller _macro = var_get_macro(_var, MTypeVarMaxLen, 51777cb4d3eSLandon J. Fuller var_get_array_len(_var)) 51877cb4d3eSLandon J. Fuller _macros[_num_macros++] = _macro 51977cb4d3eSLandon J. Fuller } 520e83ce340SAdrian Chadd } 521e83ce340SAdrian Chadd 52277cb4d3eSLandon J. Fuller # Calculate value tab alignment position for our macros 52377cb4d3eSLandon J. Fuller _tab_align = macros_get_tab_alignment(_macros, _num_macros) 524e83ce340SAdrian Chadd 52577cb4d3eSLandon J. Fuller # Write the macros 52677cb4d3eSLandon J. Fuller for (_i = 0; _i < _num_macros; _i++) 52777cb4d3eSLandon J. Fuller write_macro_define(_macros[_i], _tab_align) 52877cb4d3eSLandon J. Fuller} 52977cb4d3eSLandon J. Fuller 53077cb4d3eSLandon J. Fuller# Write the private data header (output type DATA) 53177cb4d3eSLandon J. Fullerfunction write_data(output_vars, _noutput_vars, _var, _nvram, _layouts, 53277cb4d3eSLandon J. Fuller _nlayouts, _layout, _revs, _rev, _rev_start, _rev_end, _base_type, 53377cb4d3eSLandon J. Fuller _srom_table, _nsrom_table, _i, _j) 53477cb4d3eSLandon J. Fuller{ 53577cb4d3eSLandon J. Fuller _nvram = parser_state_get_context(NVRAM) 53677cb4d3eSLandon J. Fuller _layouts = get(_nvram, p_srom_layouts) 53777cb4d3eSLandon J. Fuller _nlayouts = array_size(_layouts) 53877cb4d3eSLandon J. Fuller 53977cb4d3eSLandon J. Fuller _noutput_vars = array_size(output_vars) 54077cb4d3eSLandon J. Fuller 54177cb4d3eSLandon J. Fuller # Write all our private NVAR_ID defines 54277cb4d3eSLandon J. Fuller write_data_defines(output_vars) 54377cb4d3eSLandon J. Fuller 54477cb4d3eSLandon J. Fuller # Write all layout binding opcodes, and build an array 54577cb4d3eSLandon J. Fuller # mapping SROM revision to corresponding SROM layout 54677cb4d3eSLandon J. Fuller _srom_table = array_new() 54777cb4d3eSLandon J. Fuller for (_i = 0; _i < _nlayouts; _i++) { 54877cb4d3eSLandon J. Fuller _layout = array_get(_layouts, _i) 54977cb4d3eSLandon J. Fuller 55077cb4d3eSLandon J. Fuller # Write binding opcode table to our output file 55177cb4d3eSLandon J. Fuller write_srom_bindings(_layout) 55277cb4d3eSLandon J. Fuller 55377cb4d3eSLandon J. Fuller # Add entries to _srom_table for all covered revisions 55477cb4d3eSLandon J. Fuller _revs = get(_layout, p_revisions) 55577cb4d3eSLandon J. Fuller _rev_start = get(_revs, p_start) 55677cb4d3eSLandon J. Fuller _rev_end = get(_revs, p_end) 55777cb4d3eSLandon J. Fuller 55877cb4d3eSLandon J. Fuller for (_j = _rev_start; _j <= _rev_end; _j++) 55977cb4d3eSLandon J. Fuller array_append(_srom_table, _j) 56077cb4d3eSLandon J. Fuller } 56177cb4d3eSLandon J. Fuller 56277cb4d3eSLandon J. Fuller # Sort in ascending order, by SROM revision 56377cb4d3eSLandon J. Fuller array_sort(_srom_table) 56477cb4d3eSLandon J. Fuller _nsrom_table = array_size(_srom_table) 56577cb4d3eSLandon J. Fuller 56677cb4d3eSLandon J. Fuller # Write the variable definitions 56777cb4d3eSLandon J. Fuller emit("/* Variable definitions */\n") 56877cb4d3eSLandon J. Fuller emit("const struct bhnd_nvram_vardefn " \ 56977cb4d3eSLandon J. Fuller "bhnd_nvram_vardefns[] = {\n") 57077cb4d3eSLandon J. Fuller output_depth++ 57177cb4d3eSLandon J. Fuller for (_i = 0; _i < _noutput_vars; _i++) { 57277cb4d3eSLandon J. Fuller write_data_nvram_vardefn(array_get(output_vars, _i)) 57377cb4d3eSLandon J. Fuller } 57477cb4d3eSLandon J. Fuller output_depth-- 57577cb4d3eSLandon J. Fuller emit("};\n") 57677cb4d3eSLandon J. Fuller emit("const size_t bhnd_nvram_num_vardefns = " _noutput_vars ";\n") 57777cb4d3eSLandon J. Fuller 57877cb4d3eSLandon J. Fuller # Write static asserts for raw type constant values that must be kept 57977cb4d3eSLandon J. Fuller # synchronized with the code 58077cb4d3eSLandon J. Fuller for (_i = 0; _i < BaseTypesCount; _i++) { 58177cb4d3eSLandon J. Fuller _base_type = array_get(BaseTypesArray, _i) 58277cb4d3eSLandon J. Fuller 58377cb4d3eSLandon J. Fuller emit(sprintf("_Static_assert(%s == %u, \"%s\");\n", 58477cb4d3eSLandon J. Fuller type_get_const(_base_type), type_get_const_val(_base_type), 58577cb4d3eSLandon J. Fuller "type constant out of sync")) 58677cb4d3eSLandon J. Fuller 58777cb4d3eSLandon J. Fuller emit(sprintf("_Static_assert(%s == %u, \"%s\");\n", 58877cb4d3eSLandon J. Fuller get(_base_type, p_array_const), 58977cb4d3eSLandon J. Fuller get(_base_type, p_array_const_val), 59077cb4d3eSLandon J. Fuller "array type constant out of sync")) 59177cb4d3eSLandon J. Fuller } 59277cb4d3eSLandon J. Fuller 59377cb4d3eSLandon J. Fuller # Write all top-level bhnd_sprom_layout entries 59477cb4d3eSLandon J. Fuller emit("/* SPROM layouts */\n") 59577cb4d3eSLandon J. Fuller emit("const struct bhnd_sprom_layout bhnd_sprom_layouts[] = {\n") 59677cb4d3eSLandon J. Fuller output_depth++ 59777cb4d3eSLandon J. Fuller for (_i = 0; _i < _nsrom_table; _i++) { 59877cb4d3eSLandon J. Fuller _rev = array_get(_srom_table, _i) 59977cb4d3eSLandon J. Fuller _layout = nvram_get_srom_layout(_nvram, _rev) 60077cb4d3eSLandon J. Fuller write_data_srom_layout(_layout, _rev) 60177cb4d3eSLandon J. Fuller } 60277cb4d3eSLandon J. Fuller output_depth-- 60377cb4d3eSLandon J. Fuller emit("};\n") 60477cb4d3eSLandon J. Fuller emit("const size_t bhnd_sprom_num_layouts = " _nsrom_table ";\n") 60577cb4d3eSLandon J. Fuller} 60677cb4d3eSLandon J. Fuller 60777cb4d3eSLandon J. Fuller# Write a bhnd_nvram_vardef entry for the given variable 60877cb4d3eSLandon J. Fullerfunction write_data_nvram_vardefn(v, _desc, _help, _type, _fmt) { 60977cb4d3eSLandon J. Fuller obj_assert_class(v, Var) 61077cb4d3eSLandon J. Fuller 61177cb4d3eSLandon J. Fuller _desc = get(v, p_desc) 61277cb4d3eSLandon J. Fuller _help = get(v, p_help) 61377cb4d3eSLandon J. Fuller _type = get(v, p_type) 61477cb4d3eSLandon J. Fuller _fmt = var_get_fmt(v) 61577cb4d3eSLandon J. Fuller 61677cb4d3eSLandon J. Fuller emit("{\n") 61777cb4d3eSLandon J. Fuller output_depth++ 61877cb4d3eSLandon J. Fuller emit(sprintf(".name = \"%s\",\n", get(v, p_name))) 61977cb4d3eSLandon J. Fuller 62077cb4d3eSLandon J. Fuller if (_desc != null) 62177cb4d3eSLandon J. Fuller emit(sprintf(".desc = \"%s\",\n", get(_desc, p_value))) 62277cb4d3eSLandon J. Fuller else 62377cb4d3eSLandon J. Fuller emit(".desc = NULL,\n") 62477cb4d3eSLandon J. Fuller 62577cb4d3eSLandon J. Fuller if (_help != null) 62677cb4d3eSLandon J. Fuller emit(sprintf(".help = \"%s\",\n", get(_help, p_value))) 62777cb4d3eSLandon J. Fuller else 62877cb4d3eSLandon J. Fuller emit(".help = NULL,\n") 62977cb4d3eSLandon J. Fuller 63077cb4d3eSLandon J. Fuller emit(".type = " type_get_const(_type) ",\n") 63177cb4d3eSLandon J. Fuller emit(".nelem = " var_get_array_len(v) ",\n") 63277cb4d3eSLandon J. Fuller emit(".fmt = &" get(_fmt, p_symbol) ",\n") 63377cb4d3eSLandon J. Fuller emit(".flags = " gen_var_flags(v) ",\n") 63477cb4d3eSLandon J. Fuller 63577cb4d3eSLandon J. Fuller output_depth-- 63677cb4d3eSLandon J. Fuller emit("},\n") 63777cb4d3eSLandon J. Fuller} 63877cb4d3eSLandon J. Fuller 63977cb4d3eSLandon J. Fuller# Write a top-level bhnd_sprom_layout entry for the given revision 64077cb4d3eSLandon J. Fuller# and layout definition 64177cb4d3eSLandon J. Fullerfunction write_data_srom_layout(layout, revision, _flags, _size, 642c283839dSLandon J. Fuller _sromcrc, _crc_seg, _crc_off, 64377cb4d3eSLandon J. Fuller _sromsig, _sig_seg, _sig_offset, _sig_value, 64477cb4d3eSLandon J. Fuller _sromrev, _rev_seg, _rev_off, 64577cb4d3eSLandon J. Fuller _num_vars) 64677cb4d3eSLandon J. Fuller{ 64777cb4d3eSLandon J. Fuller _flags = array_new() 64877cb4d3eSLandon J. Fuller 64977cb4d3eSLandon J. Fuller # Calculate the size; it always follows the internal CRC variable 65077cb4d3eSLandon J. Fuller _sromcrc = srom_layout_find_entry(layout, "<sromcrc>", revision) 65177cb4d3eSLandon J. Fuller if (_sromcrc == null) { 65277cb4d3eSLandon J. Fuller errorx("missing '<sromcrc>' entry for '"revision"' layout, " \ 65377cb4d3eSLandon J. Fuller "cannot compute total size") 65477cb4d3eSLandon J. Fuller } else { 65577cb4d3eSLandon J. Fuller _crc_seg = srom_entry_get_single_segment(_sromcrc) 656c283839dSLandon J. Fuller _crc_off = get(_crc_seg, p_offset) 657c283839dSLandon J. Fuller _size = _crc_off 65877cb4d3eSLandon J. Fuller _size += get(get(_crc_seg, p_type), p_width) 65977cb4d3eSLandon J. Fuller } 66077cb4d3eSLandon J. Fuller 66177cb4d3eSLandon J. Fuller # Fetch signature definition 66277cb4d3eSLandon J. Fuller _sromsig = srom_layout_find_entry(layout, "<sromsig>", revision) 66377cb4d3eSLandon J. Fuller if (_sromsig == null) { 66477cb4d3eSLandon J. Fuller array_append(_flags, "SPROM_LAYOUT_MAGIC_NONE") 66577cb4d3eSLandon J. Fuller } else { 66677cb4d3eSLandon J. Fuller _sig_seg = srom_entry_get_single_segment(_sromsig) 66777cb4d3eSLandon J. Fuller 66877cb4d3eSLandon J. Fuller _sig_offset = get(_sig_seg, p_offset) 66977cb4d3eSLandon J. Fuller _sig_value = get(_sig_seg, p_value) 67077cb4d3eSLandon J. Fuller if (_sig_value == "") 67177cb4d3eSLandon J. Fuller errorc(get(_sromsig, p_line), "missing signature value") 67277cb4d3eSLandon J. Fuller } 67377cb4d3eSLandon J. Fuller 67477cb4d3eSLandon J. Fuller # Fetch sromrev definition 67577cb4d3eSLandon J. Fuller _sromrev = srom_layout_find_entry(layout, "sromrev", revision) 67677cb4d3eSLandon J. Fuller if (_sromrev == null) { 67777cb4d3eSLandon J. Fuller errorx("missing 'sromrev' entry for '"revision"' layout, " \ 67877cb4d3eSLandon J. Fuller "cannot determine offset") 67977cb4d3eSLandon J. Fuller } else { 68077cb4d3eSLandon J. Fuller # Must be a u8 value 68177cb4d3eSLandon J. Fuller if (!type_equal(get(_sromrev, p_type), UInt8)) { 68277cb4d3eSLandon J. Fuller errorx("'sromrev' entry has non-u8 type '" \ 68377cb4d3eSLandon J. Fuller type_to_string(get(_sromrev, p_type))) 68477cb4d3eSLandon J. Fuller } 68577cb4d3eSLandon J. Fuller 68677cb4d3eSLandon J. Fuller _rev_seg = srom_entry_get_single_segment(_sromrev) 68777cb4d3eSLandon J. Fuller _rev_off = get(_rev_seg, p_offset) 68877cb4d3eSLandon J. Fuller } 68977cb4d3eSLandon J. Fuller 69077cb4d3eSLandon J. Fuller # Write layout entry 69177cb4d3eSLandon J. Fuller emit("{\n") 69277cb4d3eSLandon J. Fuller output_depth++ 69377cb4d3eSLandon J. Fuller emit(".size = "_size",\n") 69477cb4d3eSLandon J. Fuller emit(".rev = "revision",\n") 69577cb4d3eSLandon J. Fuller 69677cb4d3eSLandon J. Fuller if (array_size(_flags) > 0) { 69777cb4d3eSLandon J. Fuller emit(".flags = " array_join(_flags, "|") ",\n") 69877cb4d3eSLandon J. Fuller } else { 69977cb4d3eSLandon J. Fuller emit(".flags = 0,\n") 70077cb4d3eSLandon J. Fuller } 70177cb4d3eSLandon J. Fuller 70277cb4d3eSLandon J. Fuller emit(".srev_offset = " _rev_off ",\n") 70377cb4d3eSLandon J. Fuller 70477cb4d3eSLandon J. Fuller if (_sromsig != null) { 70577cb4d3eSLandon J. Fuller emit(".magic_offset = " _sig_offset ",\n") 70677cb4d3eSLandon J. Fuller emit(".magic_value = " _sig_value ",\n") 70777cb4d3eSLandon J. Fuller } else { 70877cb4d3eSLandon J. Fuller emit(".magic_offset = 0,\n") 70977cb4d3eSLandon J. Fuller emit(".magic_value = 0,\n") 71077cb4d3eSLandon J. Fuller } 71177cb4d3eSLandon J. Fuller 712c283839dSLandon J. Fuller emit(".crc_offset = " _crc_off ",\n") 713c283839dSLandon J. Fuller 71477cb4d3eSLandon J. Fuller emit(".bindings = " srom_layout_get_variable_name(layout) ",\n") 71577cb4d3eSLandon J. Fuller emit(".bindings_size = nitems(" \ 71677cb4d3eSLandon J. Fuller srom_layout_get_variable_name(layout) "),\n") 71777cb4d3eSLandon J. Fuller 71877cb4d3eSLandon J. Fuller emit(".num_vars = " srom_layout_num_output_vars(layout, revision) ",\n") 71977cb4d3eSLandon J. Fuller 72077cb4d3eSLandon J. Fuller obj_delete(_flags) 72177cb4d3eSLandon J. Fuller 72277cb4d3eSLandon J. Fuller output_depth-- 72377cb4d3eSLandon J. Fuller emit("},\n"); 72477cb4d3eSLandon J. Fuller} 72577cb4d3eSLandon J. Fuller 72677cb4d3eSLandon J. Fuller# Create a new opstream encoding state instance for the given layout 72777cb4d3eSLandon J. Fullerfunction srom_ops_new(layout, _obj) { 72877cb4d3eSLandon J. Fuller obj_assert_class(layout, SromLayout) 72977cb4d3eSLandon J. Fuller 73077cb4d3eSLandon J. Fuller _obj = obj_new(SromOpStream) 73177cb4d3eSLandon J. Fuller set(_obj, p_layout, layout) 73277cb4d3eSLandon J. Fuller set(_obj, p_revisions, get(layout, p_revisions)) 73377cb4d3eSLandon J. Fuller set(_obj, p_vid, 0) 73477cb4d3eSLandon J. Fuller set(_obj, p_offset, 0) 73577cb4d3eSLandon J. Fuller set(_obj, p_type, null) 73677cb4d3eSLandon J. Fuller set(_obj, p_mask, null) 73777cb4d3eSLandon J. Fuller set(_obj, p_shift, null) 73877cb4d3eSLandon J. Fuller 73977cb4d3eSLandon J. Fuller return (_obj) 74077cb4d3eSLandon J. Fuller} 74177cb4d3eSLandon J. Fuller 74277cb4d3eSLandon J. Fuller# Return the current type width, or throw an error if no type is currently 74377cb4d3eSLandon J. Fuller# specified. 74477cb4d3eSLandon J. Fullerfunction srom_ops_get_type_width(opstream, _type) 74577cb4d3eSLandon J. Fuller{ 74677cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 74777cb4d3eSLandon J. Fuller 74877cb4d3eSLandon J. Fuller _type = get(opstream, p_type) 74977cb4d3eSLandon J. Fuller if (_type == null) 75077cb4d3eSLandon J. Fuller errorx("no type value set") 75177cb4d3eSLandon J. Fuller 75277cb4d3eSLandon J. Fuller return (get(type_get_base(_type), p_width)) 75377cb4d3eSLandon J. Fuller} 75477cb4d3eSLandon J. Fuller 75577cb4d3eSLandon J. Fuller# Write a string to the SROM opcode stream, either buffering the write, 75677cb4d3eSLandon J. Fuller# or emitting it directly. 75777cb4d3eSLandon J. Fullerfunction srom_ops_emit(opstream, string, _pending_bind, _buffer) { 75877cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 75977cb4d3eSLandon J. Fuller 76077cb4d3eSLandon J. Fuller # Buffered? 76177cb4d3eSLandon J. Fuller if ((_pending_bind = get(opstream, p_pending_bind)) != null) { 76277cb4d3eSLandon J. Fuller _buffer = get(_pending_bind, p_buffer) 76377cb4d3eSLandon J. Fuller array_append(_buffer, string) 76477cb4d3eSLandon J. Fuller return 76577cb4d3eSLandon J. Fuller } 76677cb4d3eSLandon J. Fuller 76777cb4d3eSLandon J. Fuller # Emit directly 76877cb4d3eSLandon J. Fuller emit(string) 76977cb4d3eSLandon J. Fuller} 77077cb4d3eSLandon J. Fuller 77177cb4d3eSLandon J. Fuller# Emit a SROM opcode followed by up to four optional bytes 77277cb4d3eSLandon J. Fullerfunction srom_ops_emit_opcode(opstream, opcode, arg0, arg1, arg2, arg3) { 77377cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 77477cb4d3eSLandon J. Fuller 77577cb4d3eSLandon J. Fuller srom_ops_emit(opstream, opcode",\n") 77677cb4d3eSLandon J. Fuller if (arg0 != "") srom_ops_emit(opstream, arg0",\n") 77777cb4d3eSLandon J. Fuller if (arg1 != "") srom_ops_emit(opstream, arg1",\n") 77877cb4d3eSLandon J. Fuller if (arg2 != "") srom_ops_emit(opstream, arg2",\n") 77977cb4d3eSLandon J. Fuller if (arg3 != "") srom_ops_emit(opstream, arg3",\n") 78077cb4d3eSLandon J. Fuller} 78177cb4d3eSLandon J. Fuller 78277cb4d3eSLandon J. Fuller# Emit a SROM opcode and associated integer value, choosing the best 78377cb4d3eSLandon J. Fuller# SROM_OP_DATA variant for encoding the value. 78477cb4d3eSLandon J. Fuller# 78577cb4d3eSLandon J. Fuller# opc: The standard opcode for non-IMM encoded data, or null if none 78677cb4d3eSLandon J. Fuller# opc_imm: The IMM opcode, or null if none 78777cb4d3eSLandon J. Fuller# value: The value to encode 78877cb4d3eSLandon J. Fuller# svalue: Symbolic representation of value to include in output, or null 78977cb4d3eSLandon J. Fullerfunction srom_ops_emit_int_opcode(opstream, opc, opc_imm, value, svalue, 79077cb4d3eSLandon J. Fuller _width, _offset, _delta) 79177cb4d3eSLandon J. Fuller{ 79277cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 79377cb4d3eSLandon J. Fuller 79477cb4d3eSLandon J. Fuller # Fetch current type width 79577cb4d3eSLandon J. Fuller _width = srom_ops_get_type_width(opstream) 79677cb4d3eSLandon J. Fuller 79777cb4d3eSLandon J. Fuller # Special cases: 79877cb4d3eSLandon J. Fuller if (opc_imm == SPROM_OPCODE_SHIFT_IMM) { 79977cb4d3eSLandon J. Fuller # SHIFT_IMM -- the imm value must be positive and divisible by 80077cb4d3eSLandon J. Fuller # two (shift/2) to use the IMM form. 80177cb4d3eSLandon J. Fuller if (value >= 0 && value % 2 == 0) { 80277cb4d3eSLandon J. Fuller value = (value/2) 80377cb4d3eSLandon J. Fuller opc = null 80477cb4d3eSLandon J. Fuller } else { 80577cb4d3eSLandon J. Fuller opc_imm = null 80677cb4d3eSLandon J. Fuller } 80777cb4d3eSLandon J. Fuller } else if (opc_imm == SPROM_OPCODE_OFFSET_REL_IMM) { 80877cb4d3eSLandon J. Fuller # OFFSET_REL_IMM -- the imm value must be positive, divisible 80977cb4d3eSLandon J. Fuller # by the type width, and relative to the last offset to use 81077cb4d3eSLandon J. Fuller # the IMM form. 81177cb4d3eSLandon J. Fuller 81277cb4d3eSLandon J. Fuller # Assert that callers correctly flushed any pending bind before 81377cb4d3eSLandon J. Fuller # attempting to set a relative offset 81477cb4d3eSLandon J. Fuller if (get(opstream, p_pending_bind) != null) 81577cb4d3eSLandon J. Fuller errorx("can't set relative offset with a pending bind") 81677cb4d3eSLandon J. Fuller 81777cb4d3eSLandon J. Fuller # Fetch current offset, calculate relative value and determine 81877cb4d3eSLandon J. Fuller # whether we can issue an IMM opcode 81977cb4d3eSLandon J. Fuller _offset = get(opstream, p_offset) 82077cb4d3eSLandon J. Fuller _delta = value - _offset 82177cb4d3eSLandon J. Fuller if (_delta >= 0 && 82277cb4d3eSLandon J. Fuller _delta % _width == 0 && 82377cb4d3eSLandon J. Fuller (_delta/_width) <= SPROM_OP_IMM_MAX) 82477cb4d3eSLandon J. Fuller { 82577cb4d3eSLandon J. Fuller srom_ops_emit(opstream, 82677cb4d3eSLandon J. Fuller sprintf("/* %#x + %#x -> %#x */\n", _offset, 82777cb4d3eSLandon J. Fuller _delta, value)) 82877cb4d3eSLandon J. Fuller value = (_delta / _width) 82977cb4d3eSLandon J. Fuller opc = null 83077cb4d3eSLandon J. Fuller } else { 83177cb4d3eSLandon J. Fuller opc_imm = null 83277cb4d3eSLandon J. Fuller } 83377cb4d3eSLandon J. Fuller } 83477cb4d3eSLandon J. Fuller 83577cb4d3eSLandon J. Fuller # If no symbolic representation provided, write the raw value 83677cb4d3eSLandon J. Fuller if (svalue == null) 83777cb4d3eSLandon J. Fuller svalue = value 83877cb4d3eSLandon J. Fuller 83977cb4d3eSLandon J. Fuller # Try to encode as IMM value? 84077cb4d3eSLandon J. Fuller if (opc_imm != null && value >= 0 && value <= SPROM_OP_IMM_MAX) { 84177cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, "("opc_imm"|"svalue")") 84277cb4d3eSLandon J. Fuller return 84377cb4d3eSLandon J. Fuller } 84477cb4d3eSLandon J. Fuller 84577cb4d3eSLandon J. Fuller # Can't encode as immediate; do we have a non-immediate form? 84677cb4d3eSLandon J. Fuller if (opc == null) 84777cb4d3eSLandon J. Fuller errorx("can't encode '" value "' as immediate, and no " \ 84877cb4d3eSLandon J. Fuller "non-immediate form was provided") 84977cb4d3eSLandon J. Fuller 85077cb4d3eSLandon J. Fuller # Determine and emit minimal encoding 85177cb4d3eSLandon J. Fuller # We let the C compiler perform the bit operations, rather than 85277cb4d3eSLandon J. Fuller # trying to wrestle awk's floating point arithmetic 85377cb4d3eSLandon J. Fuller if (value < 0) { 85477cb4d3eSLandon J. Fuller # Only Int8 is used 85577cb4d3eSLandon J. Fuller if (value < Int8Min) 85677cb4d3eSLandon J. Fuller errorx("cannot int8 encode '" value "'") 85777cb4d3eSLandon J. Fuller 85877cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 85977cb4d3eSLandon J. Fuller "("opc"|"SPROM_OP_DATA_I8")", svalue) 86077cb4d3eSLandon J. Fuller 86177cb4d3eSLandon J. Fuller } else if (value <= UInt8Max) { 86277cb4d3eSLandon J. Fuller 86377cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 86477cb4d3eSLandon J. Fuller "("opc"|"SPROM_OP_DATA_U8")", svalue) 86577cb4d3eSLandon J. Fuller 86677cb4d3eSLandon J. Fuller } else if (value % _width == 0 && (value / _width) <= UInt8Max) { 86777cb4d3eSLandon J. Fuller 86877cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 86977cb4d3eSLandon J. Fuller "("opc"|"SPROM_OP_DATA_U8_SCALED")", svalue / _width) 87077cb4d3eSLandon J. Fuller 87177cb4d3eSLandon J. Fuller } else if (value <= UInt16Max) { 87277cb4d3eSLandon J. Fuller 87377cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 87477cb4d3eSLandon J. Fuller "("opc"|"SPROM_OP_DATA_U16")", 87577cb4d3eSLandon J. Fuller "("svalue" & 0xFF)", 87677cb4d3eSLandon J. Fuller "("svalue" >> 8)") 87777cb4d3eSLandon J. Fuller 87877cb4d3eSLandon J. Fuller } else if (value <= UInt32Max) { 87977cb4d3eSLandon J. Fuller 88077cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 88177cb4d3eSLandon J. Fuller "("opc"|"SPROM_OP_DATA_U32")", 88277cb4d3eSLandon J. Fuller "("svalue" & 0xFF)", 88377cb4d3eSLandon J. Fuller "(("svalue" >> 8) & 0xFF)", 88477cb4d3eSLandon J. Fuller "(("svalue" >> 16) & 0xFF)", 88577cb4d3eSLandon J. Fuller "(("svalue" >> 24) & 0xFF)") 88677cb4d3eSLandon J. Fuller 88777cb4d3eSLandon J. Fuller } else { 88877cb4d3eSLandon J. Fuller errorx("can't encode '" value "' (too large)") 88977cb4d3eSLandon J. Fuller } 89077cb4d3eSLandon J. Fuller} 89177cb4d3eSLandon J. Fuller 89277cb4d3eSLandon J. Fuller# Emit initial OPCODE_VAR opcode and update opstream state 89377cb4d3eSLandon J. Fullerfunction srom_ops_reset_var(opstream, var, _vid_prev, _vid, _vid_name, 89477cb4d3eSLandon J. Fuller _type, _base_type) 89577cb4d3eSLandon J. Fuller{ 89677cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 89777cb4d3eSLandon J. Fuller obj_assert_class(var, Var) 89877cb4d3eSLandon J. Fuller 89977cb4d3eSLandon J. Fuller # Flush any pending bind for the previous variable 90077cb4d3eSLandon J. Fuller srom_ops_flush_bind(opstream, 1) 90177cb4d3eSLandon J. Fuller 90277cb4d3eSLandon J. Fuller # Fetch current state 90377cb4d3eSLandon J. Fuller _vid_prev = get(opstream, p_vid) 90477cb4d3eSLandon J. Fuller 90577cb4d3eSLandon J. Fuller _vid = get(var, p_vid) 90677cb4d3eSLandon J. Fuller _vid_name = var_get_macro_name(var, MTypeVarID) 90777cb4d3eSLandon J. Fuller 90877cb4d3eSLandon J. Fuller # Update state 90977cb4d3eSLandon J. Fuller _type = get(var, p_type) 91077cb4d3eSLandon J. Fuller set(opstream, p_vid, _vid) 91177cb4d3eSLandon J. Fuller set(opstream, p_type, type_get_base(_type)) 91277cb4d3eSLandon J. Fuller set(opstream, p_nelem, var_get_array_len(var)) 91377cb4d3eSLandon J. Fuller set(opstream, p_mask, type_get_default_mask(_type)) 91477cb4d3eSLandon J. Fuller set(opstream, p_shift, 0) 91577cb4d3eSLandon J. Fuller set(opstream, p_bind_total, 0) 91677cb4d3eSLandon J. Fuller 91777cb4d3eSLandon J. Fuller # Always provide a human readable comment 91877cb4d3eSLandon J. Fuller srom_ops_emit(opstream, sprintf("/* %s (%#x) */\n", get(var, p_name), 91977cb4d3eSLandon J. Fuller get(opstream, p_offset))) 92077cb4d3eSLandon J. Fuller 92177cb4d3eSLandon J. Fuller # Prefer a single VAR_IMM byte 92277cb4d3eSLandon J. Fuller if (_vid_prev == 0 || _vid <= SPROM_OP_IMM_MAX) { 92377cb4d3eSLandon J. Fuller srom_ops_emit_int_opcode(opstream, 92477cb4d3eSLandon J. Fuller null, SPROM_OPCODE_VAR_IMM, 92577cb4d3eSLandon J. Fuller _vid, _vid_name) 92677cb4d3eSLandon J. Fuller return 92777cb4d3eSLandon J. Fuller } 92877cb4d3eSLandon J. Fuller 92977cb4d3eSLandon J. Fuller # Try encoding as a single VAR_REL_IMM byte 93077cb4d3eSLandon J. Fuller if (_vid_prev <= _vid && (_vid - _vid_prev) <= SPROM_OP_IMM_MAX) { 93177cb4d3eSLandon J. Fuller srom_ops_emit_int_opcode(opstream, 93277cb4d3eSLandon J. Fuller null, SPROM_OPCODE_VAR_REL_IMM, 93377cb4d3eSLandon J. Fuller _vid - _vid_prev, null) 93477cb4d3eSLandon J. Fuller return 93577cb4d3eSLandon J. Fuller } 93677cb4d3eSLandon J. Fuller 93777cb4d3eSLandon J. Fuller # Fall back on a multibyte encoding 93877cb4d3eSLandon J. Fuller srom_ops_emit_int_opcode(opstream, SPROM_OPCODE_VAR, null, _vid, 93977cb4d3eSLandon J. Fuller _vid_name) 94077cb4d3eSLandon J. Fuller} 94177cb4d3eSLandon J. Fuller 94277cb4d3eSLandon J. Fuller# Emit OPCODE_REV/OPCODE_REV_RANGE (if necessary) for a new revision range 94377cb4d3eSLandon J. Fullerfunction srom_ops_emit_revisions(opstream, revisions, _prev_revs, 94477cb4d3eSLandon J. Fuller _start, _end) 94577cb4d3eSLandon J. Fuller{ 94677cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 94777cb4d3eSLandon J. Fuller _prev_revs = get(opstream, p_revisions) 94877cb4d3eSLandon J. Fuller 94977cb4d3eSLandon J. Fuller if (revrange_equal(_prev_revs, revisions)) 95077cb4d3eSLandon J. Fuller return; 95177cb4d3eSLandon J. Fuller 95277cb4d3eSLandon J. Fuller # Update stream state 95377cb4d3eSLandon J. Fuller set(opstream, p_revisions, revisions) 95477cb4d3eSLandon J. Fuller 95577cb4d3eSLandon J. Fuller _start = get(revisions, p_start) 95677cb4d3eSLandon J. Fuller _end = get(revisions, p_end) 95777cb4d3eSLandon J. Fuller 95877cb4d3eSLandon J. Fuller # Sanity-check range values 95977cb4d3eSLandon J. Fuller if (_start < 0 || _end < 0) 96077cb4d3eSLandon J. Fuller errorx("invalid range: " revrange_to_string(revisions)) 96177cb4d3eSLandon J. Fuller 96277cb4d3eSLandon J. Fuller # If range covers a single revision, and can be encoded within 96377cb4d3eSLandon J. Fuller # SROM_OP_IMM_MAX, we can use the single byte encoding 96477cb4d3eSLandon J. Fuller if (_start == _end && _start <= SPROM_OP_IMM_MAX) { 96577cb4d3eSLandon J. Fuller srom_ops_emit_int_opcode(opstream, 96677cb4d3eSLandon J. Fuller null, SPROM_OPCODE_REV_IMM, _start) 96777cb4d3eSLandon J. Fuller return 96877cb4d3eSLandon J. Fuller } 96977cb4d3eSLandon J. Fuller 97077cb4d3eSLandon J. Fuller # Otherwise, we need to use the two byte range encoding 97177cb4d3eSLandon J. Fuller if (_start > SPROM_OP_REV_RANGE_MAX || _end > SPROM_OP_REV_RANGE_MAX) { 97277cb4d3eSLandon J. Fuller errorx(sprintf("cannot encode range values %s (>= %u)", 97377cb4d3eSLandon J. Fuller revrange_to_string(revisions), SPROM_OP_REV_RANGE_MAX)) 97477cb4d3eSLandon J. Fuller } 97577cb4d3eSLandon J. Fuller 97677cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 97777cb4d3eSLandon J. Fuller SPROM_OPCODE_REV_RANGE, 97877cb4d3eSLandon J. Fuller sprintf("(%u << %s) | (%u << %s)", 97977cb4d3eSLandon J. Fuller _start, SPROM_OP_REV_START_SHIFT, 98077cb4d3eSLandon J. Fuller _end, SPROM_OP_REV_END_SHIFT)) 98177cb4d3eSLandon J. Fuller} 98277cb4d3eSLandon J. Fuller 98377cb4d3eSLandon J. Fuller# Emit OPCODE_OFFSET (if necessary) for a new offset 98477cb4d3eSLandon J. Fullerfunction srom_ops_emit_offset(opstream, offset, _prev_offset, _rel_offset, 98577cb4d3eSLandon J. Fuller _bind) 98677cb4d3eSLandon J. Fuller{ 98777cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 98877cb4d3eSLandon J. Fuller 98977cb4d3eSLandon J. Fuller # Flush any pending bind before adjusting the offset 99077cb4d3eSLandon J. Fuller srom_ops_flush_bind(opstream, 0) 99177cb4d3eSLandon J. Fuller 99277cb4d3eSLandon J. Fuller # Fetch current offset 99377cb4d3eSLandon J. Fuller _prev_offset = get(opstream, p_offset) 99477cb4d3eSLandon J. Fuller if (_prev_offset == offset) 99577cb4d3eSLandon J. Fuller return 99677cb4d3eSLandon J. Fuller 99777cb4d3eSLandon J. Fuller # Encode (possibly a relative, 1-byte form) of the offset opcode 99877cb4d3eSLandon J. Fuller srom_ops_emit_int_opcode(opstream, SPROM_OPCODE_OFFSET, 99977cb4d3eSLandon J. Fuller SPROM_OPCODE_OFFSET_REL_IMM, offset, null) 100077cb4d3eSLandon J. Fuller 100177cb4d3eSLandon J. Fuller # Update state 100277cb4d3eSLandon J. Fuller set(opstream, p_offset, offset) 100377cb4d3eSLandon J. Fuller} 100477cb4d3eSLandon J. Fuller 100577cb4d3eSLandon J. Fuller# Emit OPCODE_TYPE (if necessary) for a new type value; this also 100677cb4d3eSLandon J. Fuller# resets the mask to the type default. 100777cb4d3eSLandon J. Fullerfunction srom_ops_emit_type(opstream, type, _base_type, _prev_type, _prev_mask, 100877cb4d3eSLandon J. Fuller _default_mask) 100977cb4d3eSLandon J. Fuller{ 101077cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 101177cb4d3eSLandon J. Fuller if (!obj_is_instanceof(type, ArrayType)) 101277cb4d3eSLandon J. Fuller obj_assert_class(type, Type) 101377cb4d3eSLandon J. Fuller 101477cb4d3eSLandon J. Fuller _default_mask = type_get_default_mask(type) 101577cb4d3eSLandon J. Fuller _base_type = type_get_base(type) 101677cb4d3eSLandon J. Fuller 101777cb4d3eSLandon J. Fuller # If state already matches the requested type, nothing to be 101877cb4d3eSLandon J. Fuller # done 101977cb4d3eSLandon J. Fuller _prev_type = get(opstream, p_type) 102077cb4d3eSLandon J. Fuller _prev_mask = get(opstream, p_mask) 102177cb4d3eSLandon J. Fuller if (type_equal(_prev_type, _base_type) && _prev_mask == _default_mask) 102277cb4d3eSLandon J. Fuller return 102377cb4d3eSLandon J. Fuller 102477cb4d3eSLandon J. Fuller # Update state 102577cb4d3eSLandon J. Fuller set(opstream, p_type, _base_type) 102677cb4d3eSLandon J. Fuller set(opstream, p_mask, _default_mask) 102777cb4d3eSLandon J. Fuller 102877cb4d3eSLandon J. Fuller # Emit opcode. 102977cb4d3eSLandon J. Fuller if (type_get_const_val(_base_type) <= SPROM_OP_IMM_MAX) { 103077cb4d3eSLandon J. Fuller # Single byte IMM encoding 103177cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 103277cb4d3eSLandon J. Fuller SPROM_OPCODE_TYPE_IMM "|" type_get_const(_base_type)) 103377cb4d3eSLandon J. Fuller } else { 103477cb4d3eSLandon J. Fuller # Two byte encoding 103577cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, SPROM_OPCODE_TYPE, 103677cb4d3eSLandon J. Fuller type_get_const(_base_type)) 103777cb4d3eSLandon J. Fuller } 103877cb4d3eSLandon J. Fuller} 103977cb4d3eSLandon J. Fuller 104077cb4d3eSLandon J. Fuller# Emit OPCODE_MASK (if necessary) for a new mask value 104177cb4d3eSLandon J. Fullerfunction srom_ops_emit_mask(opstream, mask, _prev_mask) { 104277cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 104377cb4d3eSLandon J. Fuller _prev_mask = get(opstream, p_mask) 104477cb4d3eSLandon J. Fuller 104577cb4d3eSLandon J. Fuller if (_prev_mask == mask) 104677cb4d3eSLandon J. Fuller return 104777cb4d3eSLandon J. Fuller 104877cb4d3eSLandon J. Fuller set(opstream, p_mask, mask) 104977cb4d3eSLandon J. Fuller srom_ops_emit_int_opcode(opstream, 105077cb4d3eSLandon J. Fuller SPROM_OPCODE_MASK, SPROM_OPCODE_MASK_IMM, 105177cb4d3eSLandon J. Fuller mask, sprintf("0x%x", mask)) 105277cb4d3eSLandon J. Fuller} 105377cb4d3eSLandon J. Fuller 105477cb4d3eSLandon J. Fuller# Emit OPCODE_SHIFT (if necessary) for a new shift value 105577cb4d3eSLandon J. Fullerfunction srom_ops_emit_shift(opstream, shift, _prev_shift) { 105677cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 105777cb4d3eSLandon J. Fuller _prev_shift = get(opstream, p_shift) 105877cb4d3eSLandon J. Fuller 105977cb4d3eSLandon J. Fuller if (_prev_shift == shift) 106077cb4d3eSLandon J. Fuller return 106177cb4d3eSLandon J. Fuller 106277cb4d3eSLandon J. Fuller set(opstream, p_shift, shift) 106377cb4d3eSLandon J. Fuller srom_ops_emit_int_opcode(opstream, 106477cb4d3eSLandon J. Fuller SPROM_OPCODE_SHIFT, SPROM_OPCODE_SHIFT_IMM, 106577cb4d3eSLandon J. Fuller shift, null) 106677cb4d3eSLandon J. Fuller} 106777cb4d3eSLandon J. Fuller 106877cb4d3eSLandon J. Fuller# Return true if a valid BIND/BINDN encoding exists for the given SKIP_IN 106977cb4d3eSLandon J. Fuller# value, false if the skip values exceed the limits of the bind opcode 107077cb4d3eSLandon J. Fuller# family. 107177cb4d3eSLandon J. Fullerfunction srom_ops_can_encode_skip_in(skip_in) { 107277cb4d3eSLandon J. Fuller return (skip_in >= SPROM_OP_BIND_SKIP_IN_MIN && 107377cb4d3eSLandon J. Fuller skip_in <= SPROM_OP_BIND_SKIP_IN_MAX) 107477cb4d3eSLandon J. Fuller} 107577cb4d3eSLandon J. Fuller 107677cb4d3eSLandon J. Fuller# Return true if a valid BIND/BINDN encoding exists for the given SKIP_OUT 107777cb4d3eSLandon J. Fuller# value, false if the skip values exceed the limits of the bind opcode 107877cb4d3eSLandon J. Fuller# family. 107977cb4d3eSLandon J. Fullerfunction srom_ops_can_encode_skip_out(skip_out) { 108077cb4d3eSLandon J. Fuller return (skip_in >= SPROM_OP_BIND_SKIP_IN_MIN && 108177cb4d3eSLandon J. Fuller skip_in <= SPROM_OP_BIND_SKIP_IN_MAX) 108277cb4d3eSLandon J. Fuller} 108377cb4d3eSLandon J. Fuller 108477cb4d3eSLandon J. Fuller# Return true if a valid BIND/BINDN encoding exists for the given skip 108577cb4d3eSLandon J. Fuller# values, false if the skip values exceed the limits of the bind opcode 108677cb4d3eSLandon J. Fuller# family. 108777cb4d3eSLandon J. Fullerfunction srom_ops_can_encode_skip(skip_in, skip_out) { 108877cb4d3eSLandon J. Fuller return (srom_ops_can_encode_skip_in(skip_in) && 108977cb4d3eSLandon J. Fuller srom_ops_can_encode_skip_out(skip_out)) 109077cb4d3eSLandon J. Fuller} 109177cb4d3eSLandon J. Fuller 109277cb4d3eSLandon J. Fuller# Create a new SromOpBind instance for the given segment 109377cb4d3eSLandon J. Fullerfunction srom_opbind_new(segment, skip_in, skip_out, _obj, _type, _width, 109477cb4d3eSLandon J. Fuller _offset) 109577cb4d3eSLandon J. Fuller{ 109677cb4d3eSLandon J. Fuller obj_assert_class(segment, SromSegment) 109777cb4d3eSLandon J. Fuller 109877cb4d3eSLandon J. Fuller # Verify that an encoding exists for the skip values 109977cb4d3eSLandon J. Fuller if (!srom_ops_can_encode_skip_in(skip_in)) { 110077cb4d3eSLandon J. Fuller errorx(sprintf("cannot encode SKIP_IN=%d; maximum supported " \ 110177cb4d3eSLandon J. Fuller "range %d-%d", skip_in, 110277cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_IN_MIN, SPROM_OP_BIND_SKIP_IN_MAX)) 110377cb4d3eSLandon J. Fuller } 110477cb4d3eSLandon J. Fuller 110577cb4d3eSLandon J. Fuller if (!srom_ops_can_encode_skip_out(skip_out)) { 110677cb4d3eSLandon J. Fuller errorx(sprintf("cannot encode SKIP_OUT=%d; maximum supported " \ 110777cb4d3eSLandon J. Fuller "range %d-%d", skip_out, 110877cb4d3eSLandon J. Fuller SPROM_OP_BIND_SKIP_OUT_MIN, SPROM_OP_BIND_SKIP_OUT_MAX)) 110977cb4d3eSLandon J. Fuller } 111077cb4d3eSLandon J. Fuller 111177cb4d3eSLandon J. Fuller # Fetch basic segment info 111277cb4d3eSLandon J. Fuller _offset = get(segment, p_offset) 111377cb4d3eSLandon J. Fuller _type = srom_segment_get_base_type(segment) 111477cb4d3eSLandon J. Fuller _width = get(_type, p_width) 111577cb4d3eSLandon J. Fuller 111677cb4d3eSLandon J. Fuller # Construct new instance 111777cb4d3eSLandon J. Fuller _obj = obj_new(SromOpBind) 111877cb4d3eSLandon J. Fuller 111977cb4d3eSLandon J. Fuller set(_obj, p_segment, segment) 112077cb4d3eSLandon J. Fuller set(_obj, p_count, 1) 112177cb4d3eSLandon J. Fuller set(_obj, p_offset, _offset) 112277cb4d3eSLandon J. Fuller set(_obj, p_width, _width) 112377cb4d3eSLandon J. Fuller set(_obj, p_skip_in, skip_in) 112477cb4d3eSLandon J. Fuller set(_obj, p_skip_out, skip_out) 112577cb4d3eSLandon J. Fuller set(_obj, p_buffer, array_new()) 112677cb4d3eSLandon J. Fuller 112777cb4d3eSLandon J. Fuller return (_obj) 112877cb4d3eSLandon J. Fuller} 112977cb4d3eSLandon J. Fuller 113077cb4d3eSLandon J. Fuller# Try to coalesce a BIND for the given segment with an existing bind request, 113177cb4d3eSLandon J. Fuller# returning true on success, or false if the two segments cannot be coalesced 113277cb4d3eSLandon J. Fuller# into the existing request 113377cb4d3eSLandon J. Fullerfunction srom_opbind_append(bind, segment, skip_out, _bind_seg, _bind_off, 113477cb4d3eSLandon J. Fuller _width, _count, _skip_in, _seg_offset, _delta) 113577cb4d3eSLandon J. Fuller{ 113677cb4d3eSLandon J. Fuller obj_assert_class(bind, SromOpBind) 113777cb4d3eSLandon J. Fuller obj_assert_class(segment, SromSegment) 113877cb4d3eSLandon J. Fuller 113977cb4d3eSLandon J. Fuller # Are the segments compatible? 114077cb4d3eSLandon J. Fuller _bind_seg = get(bind, p_segment) 114177cb4d3eSLandon J. Fuller if (!srom_segment_attributes_equal(_bind_seg, segment)) 114277cb4d3eSLandon J. Fuller return (0) 114377cb4d3eSLandon J. Fuller 114477cb4d3eSLandon J. Fuller # Are the output skip values compatible? 114577cb4d3eSLandon J. Fuller if (get(bind, p_skip_out) != skip_out) 114677cb4d3eSLandon J. Fuller return (0) 114777cb4d3eSLandon J. Fuller 114877cb4d3eSLandon J. Fuller # Find bind offset/count/width/skip 114977cb4d3eSLandon J. Fuller _bind_off = get(bind, p_offset) 115077cb4d3eSLandon J. Fuller _count = get(bind, p_count) 115177cb4d3eSLandon J. Fuller _skip_in = get(bind, p_skip_in) 115277cb4d3eSLandon J. Fuller _width = get(bind, p_width) 115377cb4d3eSLandon J. Fuller 115477cb4d3eSLandon J. Fuller # Fetch new segment's offset 115577cb4d3eSLandon J. Fuller _seg_offset = get(segment, p_offset) 115677cb4d3eSLandon J. Fuller 115777cb4d3eSLandon J. Fuller # If there's only one segment in the bind op, we ned to compute the 115877cb4d3eSLandon J. Fuller # skip value to be used for all later segments (including the 115977cb4d3eSLandon J. Fuller # segment we're attempting to append) 116077cb4d3eSLandon J. Fuller # 116177cb4d3eSLandon J. Fuller # If there's already multiple segments, we just need to verify that 116277cb4d3eSLandon J. Fuller # the bind_offset + (count * width * skip_in) produces the new 116377cb4d3eSLandon J. Fuller # segment's offset 116477cb4d3eSLandon J. Fuller if (_count == 1) { 116577cb4d3eSLandon J. Fuller # Determine the delta between the two segment offsets. This 116677cb4d3eSLandon J. Fuller # must be a multiple of the type width to be encoded 116777cb4d3eSLandon J. Fuller # as a BINDN entry 116877cb4d3eSLandon J. Fuller _delta = _seg_offset - _bind_off 116977cb4d3eSLandon J. Fuller if ((_delta % _width) != 0) 117077cb4d3eSLandon J. Fuller return (0) 117177cb4d3eSLandon J. Fuller 117277cb4d3eSLandon J. Fuller # The skip byte count is calculated as (type width * skip) 117377cb4d3eSLandon J. Fuller _skip_in = _delta / _width 117477cb4d3eSLandon J. Fuller 117577cb4d3eSLandon J. Fuller # Is the skip encodable? 117677cb4d3eSLandon J. Fuller if (!srom_ops_can_encode_skip_in(_skip_in)) 117777cb4d3eSLandon J. Fuller return (0) 117877cb4d3eSLandon J. Fuller 117977cb4d3eSLandon J. Fuller # Save required skip 118077cb4d3eSLandon J. Fuller set(bind, p_skip_in, _skip_in) 118177cb4d3eSLandon J. Fuller } else if (_count > 1) { 118277cb4d3eSLandon J. Fuller # Get the final offset of the binding if we were to add 118377cb4d3eSLandon J. Fuller # one additional segment 118477cb4d3eSLandon J. Fuller _bind_off = _bind_off + (_width * _skip_in * (_count + 1)) 118577cb4d3eSLandon J. Fuller 118677cb4d3eSLandon J. Fuller # If it doesn't match our segment's offset, we can't 118777cb4d3eSLandon J. Fuller # append this segment 118877cb4d3eSLandon J. Fuller if (_bind_off != _seg_offset) 118977cb4d3eSLandon J. Fuller return (0) 119077cb4d3eSLandon J. Fuller } 119177cb4d3eSLandon J. Fuller 119277cb4d3eSLandon J. Fuller # Success! Increment the bind count in the existing bind 119377cb4d3eSLandon J. Fuller set(bind, p_count, _count + 1) 119477cb4d3eSLandon J. Fuller return (1) 119577cb4d3eSLandon J. Fuller} 119677cb4d3eSLandon J. Fuller 119777cb4d3eSLandon J. Fuller# Return true if the given binding operation can be omitted from the output 119877cb4d3eSLandon J. Fuller# if it would be immediately followed by a VAR, VAR_REL_IMM, or EOF opcode. 119977cb4d3eSLandon J. Fuller# 120077cb4d3eSLandon J. Fuller# The bind operatin must be configured with default count, skip_in, and 120177cb4d3eSLandon J. Fuller# skip_out values of 1, and must contain no buffered post-BIND opcodes 120277cb4d3eSLandon J. Fullerfunction srom_opbind_is_implicit_encodable(bind) { 120377cb4d3eSLandon J. Fuller obj_assert_class(bind, SromOpBind) 120477cb4d3eSLandon J. Fuller 120577cb4d3eSLandon J. Fuller if (get(bind, p_count) != 1) 120677cb4d3eSLandon J. Fuller return (0) 120777cb4d3eSLandon J. Fuller 120877cb4d3eSLandon J. Fuller if (get(bind, p_skip_in) != 1) 120977cb4d3eSLandon J. Fuller return (0) 121077cb4d3eSLandon J. Fuller 121177cb4d3eSLandon J. Fuller if (get(bind, p_skip_out) != 1) 121277cb4d3eSLandon J. Fuller return (0) 121377cb4d3eSLandon J. Fuller 121477cb4d3eSLandon J. Fuller if (array_size(get(bind, p_buffer)) != 0) 121577cb4d3eSLandon J. Fuller return (0) 121677cb4d3eSLandon J. Fuller 121777cb4d3eSLandon J. Fuller return (1) 121877cb4d3eSLandon J. Fuller} 121977cb4d3eSLandon J. Fuller 122077cb4d3eSLandon J. Fuller 122177cb4d3eSLandon J. Fuller# Encode all segment settings for a single offset segment, followed by a bind 122277cb4d3eSLandon J. Fuller# request. 122377cb4d3eSLandon J. Fuller# 122477cb4d3eSLandon J. Fuller# opstream: Opcode stream 122577cb4d3eSLandon J. Fuller# segment: Segment to be written 122677cb4d3eSLandon J. Fuller# continued: If this segment's value should be OR'd with the value of a 122777cb4d3eSLandon J. Fuller# following segment 122877cb4d3eSLandon J. Fullerfunction srom_ops_emit_segment(opstream, segment, continued, _value, 122977cb4d3eSLandon J. Fuller _bind, _skip_in, _skip_out) 123077cb4d3eSLandon J. Fuller{ 123177cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 123277cb4d3eSLandon J. Fuller obj_assert_class(segment, SromSegment) 123377cb4d3eSLandon J. Fuller 123477cb4d3eSLandon J. Fuller # Determine basic bind parameters 123577cb4d3eSLandon J. Fuller _count = 1 123677cb4d3eSLandon J. Fuller _skip_in = 1 123777cb4d3eSLandon J. Fuller _skip_out = continued ? 0 : 1 123877cb4d3eSLandon J. Fuller 123977cb4d3eSLandon J. Fuller # Try to coalesce with a pending binding 124077cb4d3eSLandon J. Fuller if ((_bind = get(opstream, p_pending_bind)) != null) { 124177cb4d3eSLandon J. Fuller if (srom_opbind_append(_bind, segment, _skip_out)) 124277cb4d3eSLandon J. Fuller return 124377cb4d3eSLandon J. Fuller } 124477cb4d3eSLandon J. Fuller 124577cb4d3eSLandon J. Fuller # Otherwise, flush any pending bind and enqueue our own 124677cb4d3eSLandon J. Fuller srom_ops_flush_bind(opstream, 0) 124777cb4d3eSLandon J. Fuller if (get(opstream, p_pending_bind)) 124877cb4d3eSLandon J. Fuller errorx("bind not flushed!") 124977cb4d3eSLandon J. Fuller 125077cb4d3eSLandon J. Fuller # Encode type 125177cb4d3eSLandon J. Fuller _value = get(segment, p_type) 125277cb4d3eSLandon J. Fuller srom_ops_emit_type(opstream, _value) 125377cb4d3eSLandon J. Fuller 125477cb4d3eSLandon J. Fuller # Encode offset 125577cb4d3eSLandon J. Fuller _value = get(segment, p_offset) 125677cb4d3eSLandon J. Fuller srom_ops_emit_offset(opstream, _value) 125777cb4d3eSLandon J. Fuller 125877cb4d3eSLandon J. Fuller # Encode mask 125977cb4d3eSLandon J. Fuller _value = get(segment, p_mask) 126077cb4d3eSLandon J. Fuller srom_ops_emit_mask(opstream, _value) 126177cb4d3eSLandon J. Fuller 126277cb4d3eSLandon J. Fuller # Encode shift 126377cb4d3eSLandon J. Fuller _value = get(segment, p_shift) 126477cb4d3eSLandon J. Fuller srom_ops_emit_shift(opstream, _value) 126577cb4d3eSLandon J. Fuller 126677cb4d3eSLandon J. Fuller # Enqueue binding with opstream 126777cb4d3eSLandon J. Fuller _bind = srom_opbind_new(segment, _skip_in, _skip_out) 126877cb4d3eSLandon J. Fuller set(opstream, p_pending_bind, _bind) 126977cb4d3eSLandon J. Fuller} 127077cb4d3eSLandon J. Fuller 127177cb4d3eSLandon J. Fuller# (private) Adjust the stream's input offset by applying the given bind 127277cb4d3eSLandon J. Fuller# operation's skip_in * width * count. 127377cb4d3eSLandon J. Fullerfunction _srom_ops_apply_bind_offset(opstream, bind, _count, _offset, _width, 127477cb4d3eSLandon J. Fuller _skip_in, _opstream_offset) 127577cb4d3eSLandon J. Fuller{ 127677cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 127777cb4d3eSLandon J. Fuller obj_assert_class(bind, SromOpBind) 127877cb4d3eSLandon J. Fuller 127977cb4d3eSLandon J. Fuller _opstream_offset = get(opstream, p_offset) 128077cb4d3eSLandon J. Fuller _offset = get(bind, p_offset) 128177cb4d3eSLandon J. Fuller if (_opstream_offset != _offset) 128277cb4d3eSLandon J. Fuller errorx("stream/bind offset state mismatch") 128377cb4d3eSLandon J. Fuller 128477cb4d3eSLandon J. Fuller _count = get(bind, p_count) 128577cb4d3eSLandon J. Fuller _width = get(bind, p_width) 128677cb4d3eSLandon J. Fuller _skip_in = get(bind, p_skip_in) 128777cb4d3eSLandon J. Fuller 128877cb4d3eSLandon J. Fuller set(opstream, p_offset, 128977cb4d3eSLandon J. Fuller _opstream_offset + ((_width * _skip_in) * _count)) 129077cb4d3eSLandon J. Fuller} 129177cb4d3eSLandon J. Fuller 129277cb4d3eSLandon J. Fuller# (private) Write a bind instance and all buffered opcodes 129377cb4d3eSLandon J. Fullerfunction _srom_ops_emit_bind(opstream, bind, _count, _skip_in, _skip_out, 129477cb4d3eSLandon J. Fuller _off_start, _width, _si_signbit, _written, _nbuffer, _buffer) 129577cb4d3eSLandon J. Fuller{ 129677cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 129777cb4d3eSLandon J. Fuller obj_assert_class(bind, SromOpBind) 129877cb4d3eSLandon J. Fuller 129977cb4d3eSLandon J. Fuller # Assert that any pending bind state has already been cleared 130077cb4d3eSLandon J. Fuller if (get(opstream, p_pending_bind) != null) 130177cb4d3eSLandon J. Fuller errorx("cannot flush bind with an existing pending_bind active") 130277cb4d3eSLandon J. Fuller 130377cb4d3eSLandon J. Fuller # Fetch (and assert valid) our skip values 130477cb4d3eSLandon J. Fuller _skip_in = get(bind, p_skip_in) 130577cb4d3eSLandon J. Fuller _skip_out = get(bind, p_skip_out) 130677cb4d3eSLandon J. Fuller 130777cb4d3eSLandon J. Fuller if (!srom_ops_can_encode_skip(_skip_in, _skip_out)) 130877cb4d3eSLandon J. Fuller errorx("invalid skip values in buffered bind") 130977cb4d3eSLandon J. Fuller 131077cb4d3eSLandon J. Fuller # Determine SKIP_IN sign bit 131177cb4d3eSLandon J. Fuller _si_signbit = "0" 131277cb4d3eSLandon J. Fuller if (_skip_in < 0) 131377cb4d3eSLandon J. Fuller _si_signbit = SPROM_OP_BIND_SKIP_IN_SIGN 131477cb4d3eSLandon J. Fuller 131577cb4d3eSLandon J. Fuller # Emit BIND/BINDN opcodes until the full count is encoded 131677cb4d3eSLandon J. Fuller _count = get(bind, p_count) 131777cb4d3eSLandon J. Fuller while (_count > 0) { 131877cb4d3eSLandon J. Fuller if (_count > 1 && _count <= SPROM_OP_IMM_MAX && 131977cb4d3eSLandon J. Fuller _skip_in == 1 && _skip_out == 1) 132077cb4d3eSLandon J. Fuller { 132177cb4d3eSLandon J. Fuller # The one-byte BINDN form requires encoding the count 132277cb4d3eSLandon J. Fuller # as a IMM, and has an implicit in/out skip of 1. 132377cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 132477cb4d3eSLandon J. Fuller "("SPROM_OPCODE_DO_BINDN_IMM"|"_count")") 132577cb4d3eSLandon J. Fuller _count -= _count 132677cb4d3eSLandon J. Fuller 132777cb4d3eSLandon J. Fuller } else if (_count > 1) { 132877cb4d3eSLandon J. Fuller # The two byte BINDN form can encode skip values and a 132977cb4d3eSLandon J. Fuller # larger U8 count 133077cb4d3eSLandon J. Fuller _written = min(_count, UInt8Max) 133177cb4d3eSLandon J. Fuller 133277cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 133377cb4d3eSLandon J. Fuller sprintf("(%s|%s|(%u<<%s)|(%u<<%s))", 133477cb4d3eSLandon J. Fuller SPROM_OPCODE_DO_BINDN, 133577cb4d3eSLandon J. Fuller _si_signbit, 133677cb4d3eSLandon J. Fuller abs(_skip_in), SPROM_OP_BIND_SKIP_IN_SHIFT, 133777cb4d3eSLandon J. Fuller _skip_out, SPROM_OP_BIND_SKIP_OUT_SHIFT), 133877cb4d3eSLandon J. Fuller _written) 133977cb4d3eSLandon J. Fuller _count -= _written 134077cb4d3eSLandon J. Fuller 134177cb4d3eSLandon J. Fuller } else { 134277cb4d3eSLandon J. Fuller # The 1-byte BIND form can encode the same SKIP values 134377cb4d3eSLandon J. Fuller # as the 2-byte BINDN, with a implicit count of 1 134477cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, 134577cb4d3eSLandon J. Fuller sprintf("(%s|%s|(%u<<%s)|(%u<<%s))", 134677cb4d3eSLandon J. Fuller SPROM_OPCODE_DO_BIND, 134777cb4d3eSLandon J. Fuller _si_signbit, 134877cb4d3eSLandon J. Fuller abs(_skip_in), SPROM_OP_BIND_SKIP_IN_SHIFT, 134977cb4d3eSLandon J. Fuller _skip_out, SPROM_OP_BIND_SKIP_OUT_SHIFT)) 135077cb4d3eSLandon J. Fuller _count-- 135177cb4d3eSLandon J. Fuller } 135277cb4d3eSLandon J. Fuller } 135377cb4d3eSLandon J. Fuller 135477cb4d3eSLandon J. Fuller # Update the stream's input offset 135577cb4d3eSLandon J. Fuller _srom_ops_apply_bind_offset(opstream, bind) 135677cb4d3eSLandon J. Fuller 135777cb4d3eSLandon J. Fuller # Write any buffered post-BIND opcodes 135877cb4d3eSLandon J. Fuller _buffer = get(bind, p_buffer) 135977cb4d3eSLandon J. Fuller _nbuffer = array_size(_buffer) 136077cb4d3eSLandon J. Fuller for (_i = 0; _i < _nbuffer; _i++) 136177cb4d3eSLandon J. Fuller srom_ops_emit(opstream, array_get(_buffer, _i)) 136277cb4d3eSLandon J. Fuller} 136377cb4d3eSLandon J. Fuller 136477cb4d3eSLandon J. Fuller# Flush any buffered binding 136577cb4d3eSLandon J. Fullerfunction srom_ops_flush_bind(opstream, allow_implicit, _bind, _bind_total) 136677cb4d3eSLandon J. Fuller{ 136777cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 136877cb4d3eSLandon J. Fuller 136977cb4d3eSLandon J. Fuller # If no pending bind, nothing to flush 137077cb4d3eSLandon J. Fuller if ((_bind = get(opstream, p_pending_bind)) == null) 137177cb4d3eSLandon J. Fuller return 137277cb4d3eSLandon J. Fuller 137377cb4d3eSLandon J. Fuller # Check the per-variable bind count to determine whether 137477cb4d3eSLandon J. Fuller # we can encode an implicit bind. 137577cb4d3eSLandon J. Fuller # 137677cb4d3eSLandon J. Fuller # If there have been any explicit bind statements, implicit binding 137777cb4d3eSLandon J. Fuller # cannot be used. 137877cb4d3eSLandon J. Fuller _bind_total = get(opstream, p_bind_total) 137977cb4d3eSLandon J. Fuller if (allow_implicit && _bind_total > 0) { 138077cb4d3eSLandon J. Fuller # Disable implicit encoding; explicit bind statements have 138177cb4d3eSLandon J. Fuller # been issued for this variable previously. 138277cb4d3eSLandon J. Fuller allow_implicit = 0 138377cb4d3eSLandon J. Fuller } 138477cb4d3eSLandon J. Fuller 138577cb4d3eSLandon J. Fuller # Increment bind count 138677cb4d3eSLandon J. Fuller set(opstream, p_bind_total, _bind_total + 1) 138777cb4d3eSLandon J. Fuller 138877cb4d3eSLandon J. Fuller # Clear the property value 138977cb4d3eSLandon J. Fuller set(opstream, p_pending_bind, null) 139077cb4d3eSLandon J. Fuller 139177cb4d3eSLandon J. Fuller # If a pending bind operation can be encoded as an implicit bind, 139277cb4d3eSLandon J. Fuller # emit a descriptive comment and update the stream state. 139377cb4d3eSLandon J. Fuller # 139477cb4d3eSLandon J. Fuller # Otherwise, emit the full set of bind opcode(s) 139577cb4d3eSLandon J. Fuller _base_off = get(opstream, p_offset) 139677cb4d3eSLandon J. Fuller if (allow_implicit && srom_opbind_is_implicit_encodable(_bind)) { 139777cb4d3eSLandon J. Fuller # Update stream's input offset 139877cb4d3eSLandon J. Fuller _srom_ops_apply_bind_offset(opstream, _bind) 139977cb4d3eSLandon J. Fuller } else { 140077cb4d3eSLandon J. Fuller _srom_ops_emit_bind(opstream, _bind) 140177cb4d3eSLandon J. Fuller } 140277cb4d3eSLandon J. Fuller 140377cb4d3eSLandon J. Fuller # Provide bind information as a comment 140477cb4d3eSLandon J. Fuller srom_ops_emit(opstream, 140577cb4d3eSLandon J. Fuller sprintf("/* bind (%s @ %#x -> %#x) */\n", 140677cb4d3eSLandon J. Fuller type_to_string(get(opstream, p_type)), 140777cb4d3eSLandon J. Fuller _base_off, get(opstream, p_offset))) 140877cb4d3eSLandon J. Fuller 140977cb4d3eSLandon J. Fuller # Clean up 141077cb4d3eSLandon J. Fuller obj_delete(_bind) 141177cb4d3eSLandon J. Fuller} 141277cb4d3eSLandon J. Fuller 141377cb4d3eSLandon J. Fuller# Write OPCODE_EOF after flushing any buffered writes 141477cb4d3eSLandon J. Fullerfunction srom_ops_emit_eof(opstream) { 141577cb4d3eSLandon J. Fuller obj_assert_class(opstream, SromOpStream) 141677cb4d3eSLandon J. Fuller 141777cb4d3eSLandon J. Fuller # Flush any buffered writes 141877cb4d3eSLandon J. Fuller srom_ops_flush_bind(opstream, 1) 141977cb4d3eSLandon J. Fuller 142077cb4d3eSLandon J. Fuller # Emit an explicit VAR_END opcode for the last entry 142177cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, SPROM_OPCODE_VAR_END) 142277cb4d3eSLandon J. Fuller 142377cb4d3eSLandon J. Fuller # Emit EOF 142477cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, SPROM_OPCODE_EOF) 142577cb4d3eSLandon J. Fuller} 142677cb4d3eSLandon J. Fuller 142777cb4d3eSLandon J. Fuller# Write the SROM offset segment bindings to the opstream 142877cb4d3eSLandon J. Fullerfunction write_srom_offset_bindings(opstream, offsets, 142977cb4d3eSLandon J. Fuller _noffsets, _offset, _segs, _nsegs, _segment, _cont, 143077cb4d3eSLandon J. Fuller _i, _j) 143177cb4d3eSLandon J. Fuller{ 143277cb4d3eSLandon J. Fuller _noffsets = array_size(offsets) 143377cb4d3eSLandon J. Fuller for (_i = 0; _i < _noffsets; _i++) { 143477cb4d3eSLandon J. Fuller # Encode each segment in this offset 143577cb4d3eSLandon J. Fuller _offset = array_get(offsets, _i) 143677cb4d3eSLandon J. Fuller _segs = get(_offset, p_segments) 143777cb4d3eSLandon J. Fuller _nsegs = array_size(_segs) 143877cb4d3eSLandon J. Fuller 143977cb4d3eSLandon J. Fuller for (_j = 0; _j < _nsegs; _j++) { 144077cb4d3eSLandon J. Fuller _segment = array_get(_segs, _j) 144177cb4d3eSLandon J. Fuller _cont = 0 144277cb4d3eSLandon J. Fuller 144377cb4d3eSLandon J. Fuller # Should this value be OR'd with the next segment? 144477cb4d3eSLandon J. Fuller if (_j+1 < _nsegs) 144577cb4d3eSLandon J. Fuller _cont = 1 144677cb4d3eSLandon J. Fuller 144777cb4d3eSLandon J. Fuller # Encode segment 144877cb4d3eSLandon J. Fuller srom_ops_emit_segment(opstream, _segment, _cont) 144977cb4d3eSLandon J. Fuller } 145077cb4d3eSLandon J. Fuller } 145177cb4d3eSLandon J. Fuller} 145277cb4d3eSLandon J. Fuller 145377cb4d3eSLandon J. Fuller# Write the SROM entry stream for a SROM entry to the output file 145477cb4d3eSLandon J. Fullerfunction write_srom_entry_bindings(entry, opstream, _var, _vid, 145577cb4d3eSLandon J. Fuller _var_type, _entry_type, _offsets, _noffsets) 145677cb4d3eSLandon J. Fuller{ 145777cb4d3eSLandon J. Fuller _var = get(entry, p_var) 145877cb4d3eSLandon J. Fuller _vid = get(_var, p_vid) 145977cb4d3eSLandon J. Fuller 146077cb4d3eSLandon J. Fuller # Encode revision switch. This resets variable state, so must 146177cb4d3eSLandon J. Fuller # occur before any variable definitions to which it applies 146277cb4d3eSLandon J. Fuller srom_ops_emit_revisions(opstream, get(entry, p_revisions)) 146377cb4d3eSLandon J. Fuller 146477cb4d3eSLandon J. Fuller # Encode variable ID 146577cb4d3eSLandon J. Fuller srom_ops_reset_var(opstream, _var, _vid) 146677cb4d3eSLandon J. Fuller output_depth++ 146777cb4d3eSLandon J. Fuller 146877cb4d3eSLandon J. Fuller # Write entry-specific array length (SROM layouts may define array 146977cb4d3eSLandon J. Fuller # mappings with fewer elements than in the variable definition) 147077cb4d3eSLandon J. Fuller if (srom_entry_has_array_type(entry)) { 147177cb4d3eSLandon J. Fuller _var_type = get(_var, p_type) 147277cb4d3eSLandon J. Fuller _entry_type = get(entry, p_type) 147377cb4d3eSLandon J. Fuller 147477cb4d3eSLandon J. Fuller # If the array length differs from the variable default, 147577cb4d3eSLandon J. Fuller # write an OPCODE_EXT_NELEM entry 147677cb4d3eSLandon J. Fuller if (type_get_nelem(_var_type) != type_get_nelem(_entry_type)) { 147777cb4d3eSLandon J. Fuller srom_ops_emit_opcode(opstream, SPROM_OPCODE_NELEM, 147877cb4d3eSLandon J. Fuller srom_entry_get_array_len(entry)) 147977cb4d3eSLandon J. Fuller } 148077cb4d3eSLandon J. Fuller } 148177cb4d3eSLandon J. Fuller 148277cb4d3eSLandon J. Fuller # Write offset segment bindings 148377cb4d3eSLandon J. Fuller _offsets = get(entry, p_offsets) 148477cb4d3eSLandon J. Fuller write_srom_offset_bindings(opstream, _offsets) 148577cb4d3eSLandon J. Fuller output_depth-- 148677cb4d3eSLandon J. Fuller} 148777cb4d3eSLandon J. Fuller 148877cb4d3eSLandon J. Fuller# Write a SROM layout binding opcode table to the output file 148977cb4d3eSLandon J. Fullerfunction write_srom_bindings(layout, _varname, _var, _all_entries, 149077cb4d3eSLandon J. Fuller _nall_entries, _entries, _nentries, _entry, _opstream, _i) 149177cb4d3eSLandon J. Fuller{ 149277cb4d3eSLandon J. Fuller _varname = srom_layout_get_variable_name(layout) 149377cb4d3eSLandon J. Fuller _all_entries = get(layout, p_entries) 149477cb4d3eSLandon J. Fuller _opstream = srom_ops_new(layout) 149577cb4d3eSLandon J. Fuller 149677cb4d3eSLandon J. Fuller # 149777cb4d3eSLandon J. Fuller # Collect all entries to be included in the output, and then 149877cb4d3eSLandon J. Fuller # sort by their variable's assigned ID (ascending). 149977cb4d3eSLandon J. Fuller # 150077cb4d3eSLandon J. Fuller # The variable IDs were previously assigned in lexigraphical sort 150177cb4d3eSLandon J. Fuller # order; since the variable *offsets* tend to match this order, this 150277cb4d3eSLandon J. Fuller # works out well for our compact encoding, allowing us to make use of 150377cb4d3eSLandon J. Fuller # compact relative encoding of both variable IDs and variable offsets. 150477cb4d3eSLandon J. Fuller # 150577cb4d3eSLandon J. Fuller _entries = array_new() 150677cb4d3eSLandon J. Fuller _nall_entries = array_size(_all_entries) 150777cb4d3eSLandon J. Fuller for (_i = 0; _i < _nall_entries; _i++) { 150877cb4d3eSLandon J. Fuller _entry = array_get(_all_entries, _i) 150977cb4d3eSLandon J. Fuller _var = get(_entry, p_var) 151077cb4d3eSLandon J. Fuller 151177cb4d3eSLandon J. Fuller # Skip internal variables 151277cb4d3eSLandon J. Fuller if (var_is_internal(_var)) 151377cb4d3eSLandon J. Fuller continue 151477cb4d3eSLandon J. Fuller 151577cb4d3eSLandon J. Fuller # Sanity check variable ID assignment 151677cb4d3eSLandon J. Fuller if (get(_var, p_vid) == "") 151777cb4d3eSLandon J. Fuller errorx("missing variable ID for " obj_to_string(_var)) 151877cb4d3eSLandon J. Fuller 151977cb4d3eSLandon J. Fuller array_append(_entries, _entry) 152077cb4d3eSLandon J. Fuller } 152177cb4d3eSLandon J. Fuller 1522abc551b1SLandon J. Fuller # Sort entries by (variable ID, revision range), ascending 1523abc551b1SLandon J. Fuller array_sort(_entries, prop_path_create(p_var, p_vid), 1524abc551b1SLandon J. Fuller prop_path_create(p_revisions, p_start), 1525abc551b1SLandon J. Fuller prop_path_create(p_revisions, p_end)) 152677cb4d3eSLandon J. Fuller 152777cb4d3eSLandon J. Fuller # Emit all entry binding opcodes 152877cb4d3eSLandon J. Fuller emit("static const uint8_t " _varname "[] = {\n") 152977cb4d3eSLandon J. Fuller output_depth++ 153077cb4d3eSLandon J. Fuller 153177cb4d3eSLandon J. Fuller _nentries = array_size(_entries) 153277cb4d3eSLandon J. Fuller for (_i = 0; _i < _nentries; _i++) { 153377cb4d3eSLandon J. Fuller _entry = array_get(_entries, _i) 153477cb4d3eSLandon J. Fuller write_srom_entry_bindings(_entry, _opstream) 153577cb4d3eSLandon J. Fuller } 153677cb4d3eSLandon J. Fuller 153777cb4d3eSLandon J. Fuller # Flush and write EOF 153877cb4d3eSLandon J. Fuller srom_ops_emit_eof(_opstream) 153977cb4d3eSLandon J. Fuller 154077cb4d3eSLandon J. Fuller output_depth-- 154177cb4d3eSLandon J. Fuller emit("};\n") 154277cb4d3eSLandon J. Fuller 154377cb4d3eSLandon J. Fuller obj_delete(_opstream) 154477cb4d3eSLandon J. Fuller obj_delete(_entries) 154577cb4d3eSLandon J. Fuller} 154677cb4d3eSLandon J. Fuller 154777cb4d3eSLandon J. Fuller# Write the BHND_NVAR_<NAME>_ID #defines to the output file 154877cb4d3eSLandon J. Fullerfunction write_data_defines(output_vars, _noutput_vars, _tab_align, _var, 154977cb4d3eSLandon J. Fuller _macro, _macros, _num_macros, _i) 155077cb4d3eSLandon J. Fuller{ 155177cb4d3eSLandon J. Fuller # Produce our array of #defines 155277cb4d3eSLandon J. Fuller _num_macros = 0 155377cb4d3eSLandon J. Fuller _noutput_vars = array_size(output_vars) 155477cb4d3eSLandon J. Fuller for (_i = 0; _i < _noutput_vars; _i++) { 155577cb4d3eSLandon J. Fuller _var = array_get(output_vars, _i) 155677cb4d3eSLandon J. Fuller 155777cb4d3eSLandon J. Fuller # Variable ID 155877cb4d3eSLandon J. Fuller _macro = var_get_macro(_var, MTypeVarID, get(_var, p_vid)) 155977cb4d3eSLandon J. Fuller _macros[_num_macros++] = _macro 156077cb4d3eSLandon J. Fuller } 156177cb4d3eSLandon J. Fuller 156277cb4d3eSLandon J. Fuller # Calculate value tab alignment position for our macros 156377cb4d3eSLandon J. Fuller _tab_align = macros_get_tab_alignment(_macros, _num_macros) 156477cb4d3eSLandon J. Fuller 156577cb4d3eSLandon J. Fuller # Write the #defines 156677cb4d3eSLandon J. Fuller emit("/* ID constants provide an index into the variable array */\n") 156777cb4d3eSLandon J. Fuller for (_i = 0; _i < _num_macros; _i++) 156877cb4d3eSLandon J. Fuller write_macro_define(_macros[_i], _tab_align) 156977cb4d3eSLandon J. Fuller emit("\n\n"); 157077cb4d3eSLandon J. Fuller} 157177cb4d3eSLandon J. Fuller 157277cb4d3eSLandon J. Fuller# Calculate the common tab alignment to be used with a set of prefix strings 157377cb4d3eSLandon J. Fuller# with the given maximum length 157477cb4d3eSLandon J. Fullerfunction tab_alignment(max_len, _tab_align) { 157577cb4d3eSLandon J. Fuller _tab_align = max_len 157677cb4d3eSLandon J. Fuller _tab_align += (TAB_WIDTH - (_tab_align % TAB_WIDTH)) % TAB_WIDTH 157777cb4d3eSLandon J. Fuller _tab_align /= TAB_WIDTH 157877cb4d3eSLandon J. Fuller 157977cb4d3eSLandon J. Fuller return (_tab_align) 158077cb4d3eSLandon J. Fuller} 158177cb4d3eSLandon J. Fuller 158277cb4d3eSLandon J. Fuller# Generate and return a tab string that can be appended to a string of 158377cb4d3eSLandon J. Fuller# `strlen` to pad the column out to `align_to` 158477cb4d3eSLandon J. Fuller# 158577cb4d3eSLandon J. Fuller# Note: If the string from which strlen was derived contains tabs, the result 158677cb4d3eSLandon J. Fuller# is undefined 158777cb4d3eSLandon J. Fullerfunction tab_str(strlen, align_to, _lead, _pad, _result, _i) { 158877cb4d3eSLandon J. Fuller _lead = strlen 158977cb4d3eSLandon J. Fuller _lead -= (_lead % TAB_WIDTH); 159077cb4d3eSLandon J. Fuller _lead /= TAB_WIDTH; 159177cb4d3eSLandon J. Fuller 159277cb4d3eSLandon J. Fuller # Determine required padding to reach the desired alignment 159377cb4d3eSLandon J. Fuller if (align_to >= _lead) 159477cb4d3eSLandon J. Fuller _pad = align_to - _lead; 159577cb4d3eSLandon J. Fuller else 159677cb4d3eSLandon J. Fuller _pad = 1; 159777cb4d3eSLandon J. Fuller 159877cb4d3eSLandon J. Fuller for (_i = 0; _i < _pad; _i++) 159977cb4d3eSLandon J. Fuller _result = _result "\t" 1600e83ce340SAdrian Chadd 1601e83ce340SAdrian Chadd return (_result) 1602e83ce340SAdrian Chadd} 1603e83ce340SAdrian Chadd 1604e83ce340SAdrian Chadd 160577cb4d3eSLandon J. Fuller# Write a MacroDefine constant, padding the constant out to `align_to` 160677cb4d3eSLandon J. Fullerfunction write_macro_define(macro, align_to, _tabstr, _i) { 160777cb4d3eSLandon J. Fuller # Determine required padding to reach the desired alignment 160877cb4d3eSLandon J. Fuller _tabstr = tab_str(length(get(macro, p_name)), align_to) 1609e83ce340SAdrian Chadd 161077cb4d3eSLandon J. Fuller emit("#define\t" get(macro, p_name) _tabstr get(macro, p_value) "\n") 1611e83ce340SAdrian Chadd} 1612e83ce340SAdrian Chadd 161377cb4d3eSLandon J. Fuller# Calculate the tab alignment to be used with a given integer-indexed array 161477cb4d3eSLandon J. Fuller# of Macro instances. 161577cb4d3eSLandon J. Fullerfunction macros_get_tab_alignment(macros, macros_len, _macro, _max_len, _i) { 161677cb4d3eSLandon J. Fuller _max_len = 0 161777cb4d3eSLandon J. Fuller for (_i = 0; _i < macros_len; _i++) { 161877cb4d3eSLandon J. Fuller _macro = macros[_i] 161977cb4d3eSLandon J. Fuller _max_len = max(_max_len, length(get(_macro, p_name))) 162077cb4d3eSLandon J. Fuller } 162177cb4d3eSLandon J. Fuller 162277cb4d3eSLandon J. Fuller return (tab_alignment(_max_len)) 162377cb4d3eSLandon J. Fuller} 162477cb4d3eSLandon J. Fuller 162577cb4d3eSLandon J. Fuller# Variable group block 162677cb4d3eSLandon J. Fuller$1 == "group" && in_parser_context(NVRAM) { 162777cb4d3eSLandon J. Fuller parse_variable_group() 162877cb4d3eSLandon J. Fuller} 162977cb4d3eSLandon J. Fuller 163077cb4d3eSLandon J. Fuller# Variable definition 163177cb4d3eSLandon J. Fuller(($1 ~ VACCESS_REGEX && $2 ~ TYPES_REGEX) || $1 ~ TYPES_REGEX) && 163277cb4d3eSLandon J. Fuller in_parser_context(SymbolContext) \ 163377cb4d3eSLandon J. Fuller{ 163477cb4d3eSLandon J. Fuller parse_variable_defn() 163577cb4d3eSLandon J. Fuller} 163677cb4d3eSLandon J. Fuller 163777cb4d3eSLandon J. Fuller# Variable "fmt" parameter 163877cb4d3eSLandon J. Fuller$1 == "fmt" && in_parser_context(Var) { 163977cb4d3eSLandon J. Fuller parse_variable_param($1) 164077cb4d3eSLandon J. Fuller next 164177cb4d3eSLandon J. Fuller} 164277cb4d3eSLandon J. Fuller 164377cb4d3eSLandon J. Fuller# Variable "all1" parameter 164477cb4d3eSLandon J. Fuller$1 == "all1" && in_parser_context(Var) { 164577cb4d3eSLandon J. Fuller parse_variable_param($1) 164677cb4d3eSLandon J. Fuller next 164777cb4d3eSLandon J. Fuller} 164877cb4d3eSLandon J. Fuller 164977cb4d3eSLandon J. Fuller# Variable desc/help parameters 165077cb4d3eSLandon J. Fuller($1 == "desc" || $1 == "help") && in_parser_context(Var) { 165177cb4d3eSLandon J. Fuller parse_variable_param($1) 165277cb4d3eSLandon J. Fuller next 165377cb4d3eSLandon J. Fuller} 165477cb4d3eSLandon J. Fuller 165577cb4d3eSLandon J. Fuller# SROM layout block 165677cb4d3eSLandon J. Fuller$1 == "srom" && in_parser_context(NVRAM) { 165777cb4d3eSLandon J. Fuller parse_srom_layout() 165877cb4d3eSLandon J. Fuller} 165977cb4d3eSLandon J. Fuller 166077cb4d3eSLandon J. Fuller 166177cb4d3eSLandon J. Fuller# SROM layout revision filter block 166277cb4d3eSLandon J. Fuller$1 == "srom" && in_parser_context(SromLayout) { 166377cb4d3eSLandon J. Fuller parse_srom_layout_filter() 166477cb4d3eSLandon J. Fuller} 166577cb4d3eSLandon J. Fuller 166677cb4d3eSLandon J. Fuller# SROM layout variable entry 166777cb4d3eSLandon J. Fuller$1 ~ "("OFF_REGEX"):$" && \ 166877cb4d3eSLandon J. Fuller (in_parser_context(SromLayout) || in_parser_context(SromLayoutFilter)) \ 166977cb4d3eSLandon J. Fuller{ 167077cb4d3eSLandon J. Fuller parse_srom_variable_entry() 167177cb4d3eSLandon J. Fuller} 167277cb4d3eSLandon J. Fuller 167377cb4d3eSLandon J. Fuller 167477cb4d3eSLandon J. Fuller# SROM entry segment 167577cb4d3eSLandon J. Fuller$1 ~ "("REL_OFF_REGEX"|"OFF_REGEX")[:,|]?" && in_parser_context(SromEntry) { 167677cb4d3eSLandon J. Fuller parse_srom_entry_segments() 167777cb4d3eSLandon J. Fuller} 167877cb4d3eSLandon J. Fuller 167977cb4d3eSLandon J. Fuller# Skip comments and blank lines 168077cb4d3eSLandon J. Fuller/^[ \t]*#/ || /^$/ { 168177cb4d3eSLandon J. Fuller next 168277cb4d3eSLandon J. Fuller} 168377cb4d3eSLandon J. Fuller 168477cb4d3eSLandon J. Fuller# Close blocks 168577cb4d3eSLandon J. Fuller/}/ && !in_parser_context(NVRAM) { 168677cb4d3eSLandon J. Fuller while (!in_parser_context(NVRAM) && $0 ~ "}") { 168777cb4d3eSLandon J. Fuller parser_state_close_block(); 168877cb4d3eSLandon J. Fuller } 168977cb4d3eSLandon J. Fuller next 169077cb4d3eSLandon J. Fuller} 169177cb4d3eSLandon J. Fuller 169277cb4d3eSLandon J. Fuller# Report unbalanced '}' 169377cb4d3eSLandon J. Fuller/}/ && in_parser_context(NVRAM) { 169477cb4d3eSLandon J. Fuller error("extra '}'") 169577cb4d3eSLandon J. Fuller} 169677cb4d3eSLandon J. Fuller 169777cb4d3eSLandon J. Fuller# Invalid variable type 169877cb4d3eSLandon J. Fuller$1 && in_parser_context(SymbolContext) { 169977cb4d3eSLandon J. Fuller error("unknown type '" $1 "'") 170077cb4d3eSLandon J. Fuller} 170177cb4d3eSLandon J. Fuller 170277cb4d3eSLandon J. Fuller# Generic parse failure 170377cb4d3eSLandon J. Fuller{ 170477cb4d3eSLandon J. Fuller error("unrecognized statement") 170577cb4d3eSLandon J. Fuller} 170677cb4d3eSLandon J. Fuller 170777cb4d3eSLandon J. Fuller# Create a class instance with the given name 170877cb4d3eSLandon J. Fullerfunction class_new(name, superclass, _class) { 170977cb4d3eSLandon J. Fuller if (_class != null) 171077cb4d3eSLandon J. Fuller errorx("class_get() must be called with one or two arguments") 171177cb4d3eSLandon J. Fuller 171277cb4d3eSLandon J. Fuller # Look for an existing class instance 171377cb4d3eSLandon J. Fuller if (name in _g_class_names) 171477cb4d3eSLandon J. Fuller errorx("redefining class: " name) 171577cb4d3eSLandon J. Fuller 171677cb4d3eSLandon J. Fuller # Create and register the class object 171777cb4d3eSLandon J. Fuller _class = obj_new(superclass) 171877cb4d3eSLandon J. Fuller _g_class_names[name] = _class 171977cb4d3eSLandon J. Fuller _g_obj[_class,OBJ_IS_CLS] = 1 172077cb4d3eSLandon J. Fuller _g_obj[_class,CLS_NAME] = name 172177cb4d3eSLandon J. Fuller 172277cb4d3eSLandon J. Fuller return (_class) 172377cb4d3eSLandon J. Fuller} 172477cb4d3eSLandon J. Fuller 172577cb4d3eSLandon J. Fuller# Return the class instance with the given name 172677cb4d3eSLandon J. Fullerfunction class_get(name) { 172777cb4d3eSLandon J. Fuller if (name in _g_class_names) 172877cb4d3eSLandon J. Fuller return (_g_class_names[name]) 172977cb4d3eSLandon J. Fuller 173077cb4d3eSLandon J. Fuller errorx("no such class " name) 173177cb4d3eSLandon J. Fuller} 173277cb4d3eSLandon J. Fuller 173377cb4d3eSLandon J. Fuller# Return the name of cls 173477cb4d3eSLandon J. Fullerfunction class_get_name(cls) { 173577cb4d3eSLandon J. Fuller if (cls == null) { 173677cb4d3eSLandon J. Fuller warnx("class_get_name() called with null class") 173777cb4d3eSLandon J. Fuller return "<null>" 173877cb4d3eSLandon J. Fuller } 173977cb4d3eSLandon J. Fuller 174077cb4d3eSLandon J. Fuller if (!obj_is_class(cls)) 174177cb4d3eSLandon J. Fuller errorx(cls " is not a class object") 174277cb4d3eSLandon J. Fuller 174377cb4d3eSLandon J. Fuller return (_g_obj[cls,CLS_NAME]) 174477cb4d3eSLandon J. Fuller} 174577cb4d3eSLandon J. Fuller 174677cb4d3eSLandon J. Fuller# Return true if the given property property ID is defined on class 174777cb4d3eSLandon J. Fullerfunction class_has_prop_id(class, prop_id, _super) { 174877cb4d3eSLandon J. Fuller if (_super != null) 174977cb4d3eSLandon J. Fuller errorx("class_has_prop_id() must be called with two arguments") 175077cb4d3eSLandon J. Fuller 175177cb4d3eSLandon J. Fuller if (class == null) 175277cb4d3eSLandon J. Fuller return (0) 175377cb4d3eSLandon J. Fuller 1754c283839dSLandon J. Fuller if (prop_id == null) 1755c283839dSLandon J. Fuller return (0) 1756c283839dSLandon J. Fuller 175777cb4d3eSLandon J. Fuller # Check class<->prop cache 175877cb4d3eSLandon J. Fuller if ((class, prop_id) in _g_class_prop_cache) 175977cb4d3eSLandon J. Fuller return (1) 176077cb4d3eSLandon J. Fuller 176177cb4d3eSLandon J. Fuller # Otherwise, slow path 176277cb4d3eSLandon J. Fuller if (!obj_is_class(class)) 176377cb4d3eSLandon J. Fuller errorx(class " is not a class object") 176477cb4d3eSLandon J. Fuller 176577cb4d3eSLandon J. Fuller if (_super != null) 176677cb4d3eSLandon J. Fuller errorx("class_has_prop_id() must be called with two arguments") 176777cb4d3eSLandon J. Fuller 176877cb4d3eSLandon J. Fuller for (_super = class; _super != null; _super = obj_get_class(_super)) { 176977cb4d3eSLandon J. Fuller if (!((_super,CLS_PROP,prop_id) in _g_obj)) 177077cb4d3eSLandon J. Fuller continue 177177cb4d3eSLandon J. Fuller 177277cb4d3eSLandon J. Fuller # Found; add to class<->prop cache 177377cb4d3eSLandon J. Fuller _g_class_prop_cache[class,prop_id] = 1 177477cb4d3eSLandon J. Fuller return (1) 177577cb4d3eSLandon J. Fuller } 177677cb4d3eSLandon J. Fuller 177777cb4d3eSLandon J. Fuller return (0) 177877cb4d3eSLandon J. Fuller} 177977cb4d3eSLandon J. Fuller 178077cb4d3eSLandon J. Fuller# Return true if the given property prop is defined on class 178177cb4d3eSLandon J. Fullerfunction class_has_property(class, prop) { 178277cb4d3eSLandon J. Fuller if (!(PROP_ID in prop)) 178377cb4d3eSLandon J. Fuller return (0) 178477cb4d3eSLandon J. Fuller 178577cb4d3eSLandon J. Fuller return (class_has_prop_id(class, prop[PROP_ID])) 178677cb4d3eSLandon J. Fuller} 178777cb4d3eSLandon J. Fuller 178877cb4d3eSLandon J. Fuller# Define a `prop` on `class` with the given `name` string 178977cb4d3eSLandon J. Fullerfunction class_add_prop(class, prop, name, _prop_id) { 179077cb4d3eSLandon J. Fuller if (_prop_id != null) 179177cb4d3eSLandon J. Fuller errorx("class_add_prop() must be called with three arguments") 179277cb4d3eSLandon J. Fuller 179377cb4d3eSLandon J. Fuller # Check for duplicate property definition 179477cb4d3eSLandon J. Fuller if (class_has_property(class, prop)) 179577cb4d3eSLandon J. Fuller errorx("property " prop[PROP_NAME] " already defined on " \ 179677cb4d3eSLandon J. Fuller class_get_name(class)) 179777cb4d3eSLandon J. Fuller 179877cb4d3eSLandon J. Fuller # Init property IDs 179977cb4d3eSLandon J. Fuller if (_g_prop_ids == null) 180077cb4d3eSLandon J. Fuller _g_prop_ids = 1 180177cb4d3eSLandon J. Fuller 180277cb4d3eSLandon J. Fuller # Get (or create) new property entry 180377cb4d3eSLandon J. Fuller if (name in _g_prop_names) { 180477cb4d3eSLandon J. Fuller _prop_id = _g_prop_names[name] 180577cb4d3eSLandon J. Fuller } else { 180677cb4d3eSLandon J. Fuller _prop_id = _g_prop_ids++ 180777cb4d3eSLandon J. Fuller _g_prop_names[name] = _prop_id 180877cb4d3eSLandon J. Fuller _g_props[_prop_id] = name 180977cb4d3eSLandon J. Fuller 181077cb4d3eSLandon J. Fuller prop[PROP_NAME] = name 181177cb4d3eSLandon J. Fuller prop[PROP_ID] = _prop_id 181277cb4d3eSLandon J. Fuller } 181377cb4d3eSLandon J. Fuller 181477cb4d3eSLandon J. Fuller # Add to class definition 181577cb4d3eSLandon J. Fuller _g_obj[class,CLS_PROP,prop[PROP_ID]] = name 181677cb4d3eSLandon J. Fuller return (name) 181777cb4d3eSLandon J. Fuller} 181877cb4d3eSLandon J. Fuller 181977cb4d3eSLandon J. Fuller# Return the property ID for a given class-defined property 182077cb4d3eSLandon J. Fullerfunction class_get_prop_id(class, prop) { 182177cb4d3eSLandon J. Fuller if (class == null) 182277cb4d3eSLandon J. Fuller errorx("class_get_prop_id() on null class") 182377cb4d3eSLandon J. Fuller 182477cb4d3eSLandon J. Fuller if (!class_has_property(class, prop)) { 182577cb4d3eSLandon J. Fuller errorx("requested undefined property '" prop[PROP_NAME] "on " \ 182677cb4d3eSLandon J. Fuller class_get_name(class)) 182777cb4d3eSLandon J. Fuller } 182877cb4d3eSLandon J. Fuller 182977cb4d3eSLandon J. Fuller return (prop[PROP_ID]) 183077cb4d3eSLandon J. Fuller} 183177cb4d3eSLandon J. Fuller 183277cb4d3eSLandon J. Fuller# Return the property ID for a given class-defined property name 183377cb4d3eSLandon J. Fullerfunction class_get_named_prop_id(class, name, _prop_id) { 183477cb4d3eSLandon J. Fuller if (class == null) 183577cb4d3eSLandon J. Fuller errorx("class_get_prop_id() on null class") 183677cb4d3eSLandon J. Fuller 183777cb4d3eSLandon J. Fuller if (!(name in _g_prop_names)) 183877cb4d3eSLandon J. Fuller errorx("requested undefined property '" name "'") 183977cb4d3eSLandon J. Fuller 184077cb4d3eSLandon J. Fuller _prop_id = _g_prop_names[name] 184177cb4d3eSLandon J. Fuller 184277cb4d3eSLandon J. Fuller if (!class_has_prop_id(class, _prop_id)) { 184377cb4d3eSLandon J. Fuller errorx("requested undefined property '" _g_props[_prop_id] \ 184477cb4d3eSLandon J. Fuller "' on " class_get_name(class)) 184577cb4d3eSLandon J. Fuller } 184677cb4d3eSLandon J. Fuller 184777cb4d3eSLandon J. Fuller return (_prop_id) 184877cb4d3eSLandon J. Fuller} 184977cb4d3eSLandon J. Fuller 185077cb4d3eSLandon J. Fuller# Create a new instance of the given class 185177cb4d3eSLandon J. Fullerfunction obj_new(class, _obj) { 185277cb4d3eSLandon J. Fuller if (_obj != null) 185377cb4d3eSLandon J. Fuller errorx("obj_new() must be called with one argument") 185477cb4d3eSLandon J. Fuller 185577cb4d3eSLandon J. Fuller if (_g_obj_ids == null) 185677cb4d3eSLandon J. Fuller _g_obj_ids = 1 185777cb4d3eSLandon J. Fuller 185877cb4d3eSLandon J. Fuller # Assign ID and set superclass 185977cb4d3eSLandon J. Fuller _obj = _g_obj_ids++ 186077cb4d3eSLandon J. Fuller _g_obj[_obj,OBJ_SUPER] = class 186177cb4d3eSLandon J. Fuller 186277cb4d3eSLandon J. Fuller return (_obj) 186377cb4d3eSLandon J. Fuller} 186477cb4d3eSLandon J. Fuller 186577cb4d3eSLandon J. Fuller# obj_delete() support for Map instances 186677cb4d3eSLandon J. Fullerfunction _obj_delete_map(obj, _prefix, _key) { 186777cb4d3eSLandon J. Fuller obj_assert_class(obj, Map) 186877cb4d3eSLandon J. Fuller _prefix = "^" obj SUBSEP 186977cb4d3eSLandon J. Fuller for (_key in _g_maps) { 187077cb4d3eSLandon J. Fuller if (!match(_key, _prefix) && _key != obj) 187177cb4d3eSLandon J. Fuller continue 187277cb4d3eSLandon J. Fuller delete _g_maps[_key] 187377cb4d3eSLandon J. Fuller } 187477cb4d3eSLandon J. Fuller} 187577cb4d3eSLandon J. Fuller 187677cb4d3eSLandon J. Fuller# obj_delete() support for Array instances 187777cb4d3eSLandon J. Fullerfunction _obj_delete_array(obj, _size, _i) { 187877cb4d3eSLandon J. Fuller obj_assert_class(obj, Array) 187977cb4d3eSLandon J. Fuller _size = array_size(obj) 188077cb4d3eSLandon J. Fuller 188177cb4d3eSLandon J. Fuller for (_i = 0; _i < _size; _i++) 188277cb4d3eSLandon J. Fuller delete _g_arrays[obj,OBJ_PROP,_i] 188377cb4d3eSLandon J. Fuller} 188477cb4d3eSLandon J. Fuller 188577cb4d3eSLandon J. Fuller# Destroy all metadata associated with the given object 188677cb4d3eSLandon J. Fullerfunction obj_delete(obj, _prop_id, _prop_name, _prefix, _key, _size, _i) { 188777cb4d3eSLandon J. Fuller if (obj_is_class(obj)) 188877cb4d3eSLandon J. Fuller errorx("cannot delete class objects") 188977cb4d3eSLandon J. Fuller 189077cb4d3eSLandon J. Fuller # Handle classes that use external global array storage 189177cb4d3eSLandon J. Fuller # for effeciency 189277cb4d3eSLandon J. Fuller if (obj_is_instanceof(obj, Map)) { 189377cb4d3eSLandon J. Fuller _obj_delete_map(obj) 189477cb4d3eSLandon J. Fuller } else if (obj_is_instanceof(obj, Array)) { 189577cb4d3eSLandon J. Fuller _obj_delete_array(obj) 189677cb4d3eSLandon J. Fuller } 189777cb4d3eSLandon J. Fuller 189877cb4d3eSLandon J. Fuller # Delete all object properties 189977cb4d3eSLandon J. Fuller for (_prop_name in _g_prop_names) { 190077cb4d3eSLandon J. Fuller if (!obj_has_prop_id(obj, _prop_id)) 190177cb4d3eSLandon J. Fuller continue 190277cb4d3eSLandon J. Fuller 190377cb4d3eSLandon J. Fuller _prop_id = _g_prop_names[_prop_name] 190477cb4d3eSLandon J. Fuller delete _g_obj[obj,OBJ_PROP,_prop_id] 190577cb4d3eSLandon J. Fuller delete _g_obj_nr[obj,OBJ_PROP,_prop_id] 190677cb4d3eSLandon J. Fuller } 190777cb4d3eSLandon J. Fuller 190877cb4d3eSLandon J. Fuller # Delete instance state 190977cb4d3eSLandon J. Fuller delete _g_obj[obj,OBJ_IS_CLS] 191077cb4d3eSLandon J. Fuller delete _g_obj[obj,OBJ_SUPER] 191177cb4d3eSLandon J. Fuller} 191277cb4d3eSLandon J. Fuller 191377cb4d3eSLandon J. Fuller# Print an object's unique ID, class, and properties to 191477cb4d3eSLandon J. Fuller# stdout 191577cb4d3eSLandon J. Fullerfunction obj_dump(obj, _pname, _prop_id, _prop_val) { 191677cb4d3eSLandon J. Fuller print(class_get_name(obj_get_class(obj)) "<" obj ">:") 191777cb4d3eSLandon J. Fuller 191877cb4d3eSLandon J. Fuller # Dump all properties 191977cb4d3eSLandon J. Fuller for (_pname in _g_prop_names) { 192077cb4d3eSLandon J. Fuller _prop_id = _g_prop_names[_pname] 192177cb4d3eSLandon J. Fuller 192277cb4d3eSLandon J. Fuller if (!obj_has_prop_id(obj, _prop_id)) 192377cb4d3eSLandon J. Fuller continue 192477cb4d3eSLandon J. Fuller 192577cb4d3eSLandon J. Fuller _prop_val = prop_get(obj, _prop_id) 192677cb4d3eSLandon J. Fuller printf("\t%s: %s\n", _pname, _prop_val) 192777cb4d3eSLandon J. Fuller } 192877cb4d3eSLandon J. Fuller} 192977cb4d3eSLandon J. Fuller 193077cb4d3eSLandon J. Fuller# Return true if obj is a class object 193177cb4d3eSLandon J. Fullerfunction obj_is_class(obj) { 193277cb4d3eSLandon J. Fuller return (_g_obj[obj,OBJ_IS_CLS] == 1) 193377cb4d3eSLandon J. Fuller} 193477cb4d3eSLandon J. Fuller 193577cb4d3eSLandon J. Fuller# Return the class of obj, if any. 193677cb4d3eSLandon J. Fullerfunction obj_get_class(obj) { 193777cb4d3eSLandon J. Fuller if (obj == null) 193877cb4d3eSLandon J. Fuller errorx("obj_get_class() on null object") 193977cb4d3eSLandon J. Fuller return (_g_obj[obj,OBJ_SUPER]) 194077cb4d3eSLandon J. Fuller} 194177cb4d3eSLandon J. Fuller 194277cb4d3eSLandon J. Fuller# Return true if obj is an instance of the given class 194377cb4d3eSLandon J. Fullerfunction obj_is_instanceof(obj, class, _super) { 194477cb4d3eSLandon J. Fuller if (_super != null) 194577cb4d3eSLandon J. Fuller errorx("obj_is_instanceof() must be called with two arguments") 194677cb4d3eSLandon J. Fuller 194777cb4d3eSLandon J. Fuller if (!obj_is_class(class)) 194877cb4d3eSLandon J. Fuller errorx(class " is not a class object") 194977cb4d3eSLandon J. Fuller 195077cb4d3eSLandon J. Fuller if (obj == null) { 195177cb4d3eSLandon J. Fuller errorx("obj_is_instanceof() called with null obj (class " \ 195277cb4d3eSLandon J. Fuller class_get_name(class) ")") 195377cb4d3eSLandon J. Fuller } 195477cb4d3eSLandon J. Fuller 195577cb4d3eSLandon J. Fuller for (_super = obj_get_class(obj); _super != null; 195677cb4d3eSLandon J. Fuller _super = obj_get_class(_super)) 195777cb4d3eSLandon J. Fuller { 195877cb4d3eSLandon J. Fuller if (_super == class) 195977cb4d3eSLandon J. Fuller return (1) 196077cb4d3eSLandon J. Fuller } 196177cb4d3eSLandon J. Fuller 196277cb4d3eSLandon J. Fuller return (0) 196377cb4d3eSLandon J. Fuller} 196477cb4d3eSLandon J. Fuller 196577cb4d3eSLandon J. Fuller# Default object shallow equality implementation. Returns true if the two 196677cb4d3eSLandon J. Fuller# objects share a common superclass and have identity equality across all defined 196777cb4d3eSLandon J. Fuller# properties. 196877cb4d3eSLandon J. Fullerfunction obj_trivially_equal(lhs, rhs, _class, _pname, _prop_id) { 196977cb4d3eSLandon J. Fuller # Simple case 197077cb4d3eSLandon J. Fuller if (lhs == rhs) 197177cb4d3eSLandon J. Fuller return (1) 197277cb4d3eSLandon J. Fuller 197377cb4d3eSLandon J. Fuller # Must share a common superclass 197477cb4d3eSLandon J. Fuller _class = obj_get_class(lhs) 197577cb4d3eSLandon J. Fuller if (_class != obj_get_class(rhs)) 197677cb4d3eSLandon J. Fuller return (0) 197777cb4d3eSLandon J. Fuller 197877cb4d3eSLandon J. Fuller # Compare all properties 197977cb4d3eSLandon J. Fuller _prop_count = 0 198077cb4d3eSLandon J. Fuller for (_pname in _g_prop_names) { 198177cb4d3eSLandon J. Fuller _prop_id = _g_prop_names[_pname] 198277cb4d3eSLandon J. Fuller 198377cb4d3eSLandon J. Fuller if (!class_has_prop_id(_class, _prop_id)) 198477cb4d3eSLandon J. Fuller continue 198577cb4d3eSLandon J. Fuller 198677cb4d3eSLandon J. Fuller if (prop_get(lhs, _prop_id) != prop_get(rhs, _prop_id)) 198777cb4d3eSLandon J. Fuller return (0) 198877cb4d3eSLandon J. Fuller } 198977cb4d3eSLandon J. Fuller 199077cb4d3eSLandon J. Fuller # All properties are trivially equal 199177cb4d3eSLandon J. Fuller return (1) 199277cb4d3eSLandon J. Fuller} 199377cb4d3eSLandon J. Fuller 199477cb4d3eSLandon J. Fuller 199577cb4d3eSLandon J. Fuller# Return a debug string representation of an object's unique ID, class, and 199677cb4d3eSLandon J. Fuller# properties 199777cb4d3eSLandon J. Fullerfunction obj_to_string(obj, _pname, _prop_id, _prop_val, _prop_count, _result) { 199877cb4d3eSLandon J. Fuller _result = class_get_name(obj_get_class(obj)) "<" obj ">: { " 199977cb4d3eSLandon J. Fuller 200077cb4d3eSLandon J. Fuller # Fetch all properties 200177cb4d3eSLandon J. Fuller _prop_count = 0 200277cb4d3eSLandon J. Fuller for (_pname in _g_prop_names) { 200377cb4d3eSLandon J. Fuller _prop_id = _g_prop_names[_pname] 200477cb4d3eSLandon J. Fuller 200577cb4d3eSLandon J. Fuller if (!obj_has_prop_id(obj, _prop_id)) 200677cb4d3eSLandon J. Fuller continue 200777cb4d3eSLandon J. Fuller 200877cb4d3eSLandon J. Fuller if (_prop_count >= 0) 200977cb4d3eSLandon J. Fuller _result = _result ", " 201077cb4d3eSLandon J. Fuller 201177cb4d3eSLandon J. Fuller _result = _result sprintf("\t%s: %s\n", _pname, _prop_val) 201277cb4d3eSLandon J. Fuller _prop_count++ 201377cb4d3eSLandon J. Fuller } 201477cb4d3eSLandon J. Fuller 201577cb4d3eSLandon J. Fuller return (_result " }") 201677cb4d3eSLandon J. Fuller} 201777cb4d3eSLandon J. Fuller 201877cb4d3eSLandon J. Fuller# Assert that obj is an instance of the given class 201977cb4d3eSLandon J. Fullerfunction obj_assert_class(obj, class) { 202077cb4d3eSLandon J. Fuller if (!obj_is_instanceof(obj, class)) { 202177cb4d3eSLandon J. Fuller errorx(class_get_name(obj_get_class(obj)) "<" obj "> is not " \ 202277cb4d3eSLandon J. Fuller "an instance of " class_get_name(class)) 202377cb4d3eSLandon J. Fuller } 202477cb4d3eSLandon J. Fuller} 202577cb4d3eSLandon J. Fuller 202677cb4d3eSLandon J. Fuller# Return true if the given property prop is defined by the object's superclass 202777cb4d3eSLandon J. Fullerfunction obj_has_property(obj, prop, _class) { 202877cb4d3eSLandon J. Fuller if (obj == null) 202977cb4d3eSLandon J. Fuller errorx("obj_has_property() on null object") 203077cb4d3eSLandon J. Fuller 203177cb4d3eSLandon J. Fuller _class = obj_get_class(obj) 203277cb4d3eSLandon J. Fuller return (class_has_property(_class, prop)) 203377cb4d3eSLandon J. Fuller} 203477cb4d3eSLandon J. Fuller 203577cb4d3eSLandon J. Fuller# Return true if the given property ID is defined by the object's superclass 203677cb4d3eSLandon J. Fullerfunction obj_has_prop_id(obj, prop_id, _class) { 203777cb4d3eSLandon J. Fuller if (obj == null) 203877cb4d3eSLandon J. Fuller errorx("obj_has_prop_id() on null object") 203977cb4d3eSLandon J. Fuller 204077cb4d3eSLandon J. Fuller _class = obj_get_class(obj) 204177cb4d3eSLandon J. Fuller return (class_has_prop_id(_class, prop_id)) 204277cb4d3eSLandon J. Fuller} 204377cb4d3eSLandon J. Fuller 204477cb4d3eSLandon J. Fuller# Return the line (NR) at which a given property ID was set on the object 204577cb4d3eSLandon J. Fuller# Will throw an error if the property has not been set on obj 204677cb4d3eSLandon J. Fullerfunction obj_get_prop_id_nr(obj, prop_id) { 204777cb4d3eSLandon J. Fuller if (obj == null) 204877cb4d3eSLandon J. Fuller errorx("obj_get_prop_id_nr() on null object") 204977cb4d3eSLandon J. Fuller 205077cb4d3eSLandon J. Fuller if (!obj_has_prop_id(obj, prop_id)) { 205177cb4d3eSLandon J. Fuller errorx("requested undefined property '" _g_props[prop_id] \ 205277cb4d3eSLandon J. Fuller "' (" prop_id ") on " obj_to_string(obj)) 205377cb4d3eSLandon J. Fuller } 205477cb4d3eSLandon J. Fuller 205577cb4d3eSLandon J. Fuller # Fetch NR 205677cb4d3eSLandon J. Fuller if ((obj,OBJ_PROP,prop_id) in _g_obj_nr) 205777cb4d3eSLandon J. Fuller return (_g_obj_nr[obj,OBJ_PROP,prop_id]) 205877cb4d3eSLandon J. Fuller 205977cb4d3eSLandon J. Fuller errorx("property '" _g_props[prop_id] "' (" prop_id ") not " \ 206077cb4d3eSLandon J. Fuller "previously set on " obj_to_string(obj)) 206177cb4d3eSLandon J. Fuller} 206277cb4d3eSLandon J. Fuller 206377cb4d3eSLandon J. Fuller# Return the line (NR) at which a given property was set on the object 206477cb4d3eSLandon J. Fuller# Will throw an error if the property has not been set on obj 206577cb4d3eSLandon J. Fullerfunction obj_get_prop_nr(obj, prop) { 206677cb4d3eSLandon J. Fuller return (obj_get_prop_id_nr(obj, prop[PROP_ID])) 206777cb4d3eSLandon J. Fuller} 206877cb4d3eSLandon J. Fuller 206977cb4d3eSLandon J. Fuller# Return an abstract property ID for a given property 207077cb4d3eSLandon J. Fullerfunction obj_get_prop_id(obj, prop) { 207177cb4d3eSLandon J. Fuller if (obj == null) 207277cb4d3eSLandon J. Fuller errorx("obj_get_prop_id() on null object") 207377cb4d3eSLandon J. Fuller 207477cb4d3eSLandon J. Fuller return (class_get_prop_id(obj_get_class(obj), prop)) 207577cb4d3eSLandon J. Fuller} 207677cb4d3eSLandon J. Fuller 207777cb4d3eSLandon J. Fuller 207877cb4d3eSLandon J. Fuller# Return the property ID for a given property name 207977cb4d3eSLandon J. Fullerfunction obj_get_named_prop_id(obj, name) { 208077cb4d3eSLandon J. Fuller if (obj == null) 208177cb4d3eSLandon J. Fuller errorx("obj_get_named_prop_id() on null object") 208277cb4d3eSLandon J. Fuller 208377cb4d3eSLandon J. Fuller return (class_get_named_prop_id(obj_get_class(obj), name)) 208477cb4d3eSLandon J. Fuller} 208577cb4d3eSLandon J. Fuller 208677cb4d3eSLandon J. Fuller# Set a property on obj 208777cb4d3eSLandon J. Fullerfunction set(obj, prop, value, _class) { 208877cb4d3eSLandon J. Fuller return (prop_set(obj, prop[PROP_ID], value)) 208977cb4d3eSLandon J. Fuller} 209077cb4d3eSLandon J. Fuller 209177cb4d3eSLandon J. Fuller# Get a property value defined on obj 209277cb4d3eSLandon J. Fullerfunction get(obj, prop, _class) { 209377cb4d3eSLandon J. Fuller return (prop_get(obj, prop[PROP_ID])) 209477cb4d3eSLandon J. Fuller} 209577cb4d3eSLandon J. Fuller 209677cb4d3eSLandon J. Fuller# Set a property on obj, using a property ID returned by obj_get_prop_id() or 209777cb4d3eSLandon J. Fuller# class_get_prop_id() 209877cb4d3eSLandon J. Fullerfunction prop_set(obj, prop_id, value, _class) { 209977cb4d3eSLandon J. Fuller if (obj == null) { 210077cb4d3eSLandon J. Fuller errorx("setting property '" _g_props[prop_id] \ 210177cb4d3eSLandon J. Fuller "' on null object") 210277cb4d3eSLandon J. Fuller } 210377cb4d3eSLandon J. Fuller 210477cb4d3eSLandon J. Fuller _class = obj_get_class(obj) 210577cb4d3eSLandon J. Fuller if (_class == null) 210677cb4d3eSLandon J. Fuller errorx(obj " has no superclass") 210777cb4d3eSLandon J. Fuller 210877cb4d3eSLandon J. Fuller if (!class_has_prop_id(_class, prop_id)) { 210977cb4d3eSLandon J. Fuller errorx("requested undefined property '" _g_props[prop_id] \ 211077cb4d3eSLandon J. Fuller "' (" prop_id ") on " class_get_name(_class)) 211177cb4d3eSLandon J. Fuller } 211277cb4d3eSLandon J. Fuller 211377cb4d3eSLandon J. Fuller # Track the line on which the property was set 211477cb4d3eSLandon J. Fuller _g_obj_nr[obj,OBJ_PROP,prop_id] = NR 211577cb4d3eSLandon J. Fuller _g_obj[obj,OBJ_PROP,prop_id] = value 211677cb4d3eSLandon J. Fuller} 211777cb4d3eSLandon J. Fuller 211877cb4d3eSLandon J. Fuller# Convert a property ID to a property path. 211977cb4d3eSLandon J. Fullerfunction prop_id_to_path(prop_id) { 212077cb4d3eSLandon J. Fuller if (!(prop_id in _g_props)) 212177cb4d3eSLandon J. Fuller errorx("'" prop_id "' is not a property ID") 212277cb4d3eSLandon J. Fuller 212377cb4d3eSLandon J. Fuller # Convert to path string representation 212477cb4d3eSLandon J. Fuller return (""prop_id) 212577cb4d3eSLandon J. Fuller} 212677cb4d3eSLandon J. Fuller 212777cb4d3eSLandon J. Fuller# Convert a property to a property path. 212877cb4d3eSLandon J. Fullerfunction prop_to_path(prop) { 212977cb4d3eSLandon J. Fuller if (!(PROP_ID in prop)) 213077cb4d3eSLandon J. Fuller errorx("prop_to_path() called with non-property head") 213177cb4d3eSLandon J. Fuller 213277cb4d3eSLandon J. Fuller return (prop_id_to_path(prop[PROP_ID])) 213377cb4d3eSLandon J. Fuller} 213477cb4d3eSLandon J. Fuller 213577cb4d3eSLandon J. Fuller# Create a property path from head and tail properties 213677cb4d3eSLandon J. Fuller# Additional properties may be appended via prop_path_append() or 213777cb4d3eSLandon J. Fuller# prop_path_append_id() 213877cb4d3eSLandon J. Fullerfunction prop_path_create(head, tail) { 213977cb4d3eSLandon J. Fuller if (!(PROP_ID in head)) 214077cb4d3eSLandon J. Fuller errorx("prop_path() called with non-property head") 214177cb4d3eSLandon J. Fuller 214277cb4d3eSLandon J. Fuller if (!(PROP_ID in tail)) 214377cb4d3eSLandon J. Fuller errorx("prop_path() called with non-property tail") 214477cb4d3eSLandon J. Fuller 214577cb4d3eSLandon J. Fuller return (head[PROP_ID] SUBSEP tail[PROP_ID]) 214677cb4d3eSLandon J. Fuller} 214777cb4d3eSLandon J. Fuller 214877cb4d3eSLandon J. Fuller# Append a property to the given property path 214977cb4d3eSLandon J. Fullerfunction prop_path_append(path, tail) { 215077cb4d3eSLandon J. Fuller if (!(PROP_ID in tail)) 215177cb4d3eSLandon J. Fuller errorx("prop_path_append() called with non-property tail") 215277cb4d3eSLandon J. Fuller 215377cb4d3eSLandon J. Fuller return (prop_path_append_id(path, tail[PROP_ID])) 215477cb4d3eSLandon J. Fuller} 215577cb4d3eSLandon J. Fuller 215677cb4d3eSLandon J. Fuller# Append a property ID to the given property path 215777cb4d3eSLandon J. Fullerfunction prop_path_append_id(path, tail_id) { 215877cb4d3eSLandon J. Fuller if (!(tail_id in _g_props)) 215977cb4d3eSLandon J. Fuller errorx("'" tail_id "' is not a property ID") 216077cb4d3eSLandon J. Fuller 216177cb4d3eSLandon J. Fuller return (path SUBSEP tail_id) 216277cb4d3eSLandon J. Fuller} 216377cb4d3eSLandon J. Fuller 216477cb4d3eSLandon J. Fuller# Fetch a value from obj using a property path previously returned by 216577cb4d3eSLandon J. Fuller# prop_path_create(), prop_to_path(), etc. 216677cb4d3eSLandon J. Fullerfunction prop_get_path(obj, prop_path, _class, _prop_ids, _nprop_ids, _next, 216777cb4d3eSLandon J. Fuller _prop_head, _prop_len, _prop_tail) 216877cb4d3eSLandon J. Fuller{ 216977cb4d3eSLandon J. Fuller if (obj == null) { 217077cb4d3eSLandon J. Fuller errorx("requested property path '" \ 217177cb4d3eSLandon J. Fuller gsub(SUBSEP, ".", prop_path) "' on null object") 217277cb4d3eSLandon J. Fuller } 217377cb4d3eSLandon J. Fuller 217477cb4d3eSLandon J. Fuller # Try the cache first 217577cb4d3eSLandon J. Fuller _class = obj_get_class(obj) 217677cb4d3eSLandon J. Fuller if ((_class,prop_path,PPATH_HEAD) in _g_ppath_cache) { 217777cb4d3eSLandon J. Fuller _prop_head = _g_ppath_cache[_class,prop_path,PPATH_HEAD] 217877cb4d3eSLandon J. Fuller _next = prop_get(obj, _prop_head) 217977cb4d3eSLandon J. Fuller 218077cb4d3eSLandon J. Fuller if ((_class,prop_path,PPATH_TAIL) in _g_ppath_cache) { 218177cb4d3eSLandon J. Fuller _prop_tail = _g_ppath_cache[_class,prop_path,PPATH_TAIL] 218277cb4d3eSLandon J. Fuller return (prop_get_path(_next, _prop_tail)) 218377cb4d3eSLandon J. Fuller } 218477cb4d3eSLandon J. Fuller 218577cb4d3eSLandon J. Fuller return (_next) 218677cb4d3eSLandon J. Fuller } 218777cb4d3eSLandon J. Fuller 218877cb4d3eSLandon J. Fuller # Parse the head/tail of the property path and add to cache 218977cb4d3eSLandon J. Fuller _nprop_ids = split(prop_path, _prop_ids, SUBSEP) 219077cb4d3eSLandon J. Fuller if (_nprop_ids == 0) 219177cb4d3eSLandon J. Fuller errorx("empty property path") 219277cb4d3eSLandon J. Fuller _prop_head = _prop_ids[1] 219377cb4d3eSLandon J. Fuller _g_ppath_cache[_class,prop_path,PPATH_HEAD] = _prop_head 219477cb4d3eSLandon J. Fuller 219577cb4d3eSLandon J. Fuller if (_nprop_ids > 1) { 219677cb4d3eSLandon J. Fuller _prop_len = length(_prop_head) 219777cb4d3eSLandon J. Fuller _prop_tail = substr(prop_path, _prop_len+2) 219877cb4d3eSLandon J. Fuller 219977cb4d3eSLandon J. Fuller # Add to cache 220077cb4d3eSLandon J. Fuller _g_ppath_cache[_class,prop_path,PPATH_TAIL] = _prop_tail 220177cb4d3eSLandon J. Fuller } 220277cb4d3eSLandon J. Fuller 220377cb4d3eSLandon J. Fuller # Recursively call out implementation, this time fetching from 220477cb4d3eSLandon J. Fuller # cache 220577cb4d3eSLandon J. Fuller return (prop_get_path(obj, prop_path)) 220677cb4d3eSLandon J. Fuller} 220777cb4d3eSLandon J. Fuller 220877cb4d3eSLandon J. Fuller# Fetch a value property value from obj, using a property ID returned by 220977cb4d3eSLandon J. Fuller# obj_get_prop_id() or class_get_prop_id() 221077cb4d3eSLandon J. Fullerfunction prop_get(obj, prop_id, _class) { 221177cb4d3eSLandon J. Fuller if (obj == null) { 221277cb4d3eSLandon J. Fuller errorx("requested property '" _g_props[prop_id] \ 221377cb4d3eSLandon J. Fuller "' on null object") 221477cb4d3eSLandon J. Fuller } 221577cb4d3eSLandon J. Fuller 221677cb4d3eSLandon J. Fuller _class = obj_get_class(obj) 221777cb4d3eSLandon J. Fuller if (_class == null) 221877cb4d3eSLandon J. Fuller errorx(obj " has no superclass") 221977cb4d3eSLandon J. Fuller 222077cb4d3eSLandon J. Fuller if (!class_has_prop_id(_class, prop_id)) { 222177cb4d3eSLandon J. Fuller errorx("requested undefined property '" _g_props[prop_id] \ 222277cb4d3eSLandon J. Fuller "' (" prop_id ") on " class_get_name(_class)) 222377cb4d3eSLandon J. Fuller } 222477cb4d3eSLandon J. Fuller 222577cb4d3eSLandon J. Fuller return (_g_obj[obj,OBJ_PROP,prop_id]) 222677cb4d3eSLandon J. Fuller} 222777cb4d3eSLandon J. Fuller 222877cb4d3eSLandon J. Fuller# Create a new MacroType instance 222977cb4d3eSLandon J. Fullerfunction macro_type_new(name, const_suffix, _obj) { 223077cb4d3eSLandon J. Fuller _obj = obj_new(MacroType) 223177cb4d3eSLandon J. Fuller 223277cb4d3eSLandon J. Fuller set(_obj, p_name, name) 223377cb4d3eSLandon J. Fuller set(_obj, p_const_suffix, const_suffix) 223477cb4d3eSLandon J. Fuller 223577cb4d3eSLandon J. Fuller return (_obj) 223677cb4d3eSLandon J. Fuller} 223777cb4d3eSLandon J. Fuller 223877cb4d3eSLandon J. Fuller# Create a new MacroDefine instance 223977cb4d3eSLandon J. Fullerfunction macro_new(name, value, _obj) { 224077cb4d3eSLandon J. Fuller _obj = obj_new(MacroDefine) 224177cb4d3eSLandon J. Fuller set(_obj, p_name, name) 224277cb4d3eSLandon J. Fuller set(_obj, p_value, value) 224377cb4d3eSLandon J. Fuller 224477cb4d3eSLandon J. Fuller return (_obj) 224577cb4d3eSLandon J. Fuller} 224677cb4d3eSLandon J. Fuller 224777cb4d3eSLandon J. Fuller# Create an empty array; this uses _g_arrays to store integer 224877cb4d3eSLandon J. Fuller# keys/values under the object's property prefix. 224977cb4d3eSLandon J. Fullerfunction array_new(_obj) { 225077cb4d3eSLandon J. Fuller _obj = obj_new(Array) 225177cb4d3eSLandon J. Fuller set(_obj, p_count, 0) 225277cb4d3eSLandon J. Fuller 225377cb4d3eSLandon J. Fuller return (_obj) 225477cb4d3eSLandon J. Fuller} 225577cb4d3eSLandon J. Fuller 225677cb4d3eSLandon J. Fuller# Return the number of elements in the array 225777cb4d3eSLandon J. Fullerfunction array_size(array) { 225877cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 225977cb4d3eSLandon J. Fuller return (get(array, p_count)) 226077cb4d3eSLandon J. Fuller} 226177cb4d3eSLandon J. Fuller 226277cb4d3eSLandon J. Fuller# Return true if the array is empty 226377cb4d3eSLandon J. Fullerfunction array_empty(array) { 226477cb4d3eSLandon J. Fuller return (array_size(array) == 0) 226577cb4d3eSLandon J. Fuller} 226677cb4d3eSLandon J. Fuller 226777cb4d3eSLandon J. Fuller# Append a value to the array 226877cb4d3eSLandon J. Fullerfunction array_append(array, value, _i) { 226977cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 227077cb4d3eSLandon J. Fuller 227177cb4d3eSLandon J. Fuller _i = get(array, p_count) 227277cb4d3eSLandon J. Fuller _g_arrays[array,OBJ_PROP,_i] = value 227377cb4d3eSLandon J. Fuller set(array, p_count, _i+1) 227477cb4d3eSLandon J. Fuller} 227577cb4d3eSLandon J. Fuller 227677cb4d3eSLandon J. Fuller# Set an array value 227777cb4d3eSLandon J. Fuller# An error will be thrown if the idx is outside array bounds 227877cb4d3eSLandon J. Fullerfunction array_set(array, idx, value) { 227977cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 228077cb4d3eSLandon J. Fuller 228177cb4d3eSLandon J. Fuller if (!((array,OBJ_PROP,idx) in _g_arrays)) 228277cb4d3eSLandon J. Fuller errorx(idx " out of range of array " obj_to_string(array)) 228377cb4d3eSLandon J. Fuller 228477cb4d3eSLandon J. Fuller _g_arrays[array,OBJ_PROP,idx] = value 228577cb4d3eSLandon J. Fuller} 228677cb4d3eSLandon J. Fuller 228777cb4d3eSLandon J. Fuller# Return value at the given index from the array 228877cb4d3eSLandon J. Fuller# An error will be thrown if 'idx' is outside the array bounds 228977cb4d3eSLandon J. Fullerfunction array_get(array, idx) { 229077cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 229177cb4d3eSLandon J. Fuller 229277cb4d3eSLandon J. Fuller if (!((array,OBJ_PROP,idx) in _g_arrays)) 229377cb4d3eSLandon J. Fuller errorx(idx " out of range of array " obj_to_string(array)) 229477cb4d3eSLandon J. Fuller 229577cb4d3eSLandon J. Fuller return (_g_arrays[array,OBJ_PROP,idx]) 229677cb4d3eSLandon J. Fuller} 229777cb4d3eSLandon J. Fuller 229877cb4d3eSLandon J. Fuller 229977cb4d3eSLandon J. Fuller# 230077cb4d3eSLandon J. Fuller# Sort an array, using standard awk comparison operators over its values. 230177cb4d3eSLandon J. Fuller# 2302abc551b1SLandon J. Fuller# If `prop_path*` is non-NULL, the corresponding property path (or property ID) 230377cb4d3eSLandon J. Fuller# will be fetched from each array element and used as the sorting value. 230477cb4d3eSLandon J. Fuller# 2305abc551b1SLandon J. Fuller# If multiple property paths are specified, the array is first sorted by 2306abc551b1SLandon J. Fuller# the first path, and then any equal values are sorted by the second path, 2307abc551b1SLandon J. Fuller# and so on. 2308abc551b1SLandon J. Fuller# 2309abc551b1SLandon J. Fullerfunction array_sort(array, prop_path0, prop_path1, prop_path2, _size) { 231077cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 231177cb4d3eSLandon J. Fuller 2312abc551b1SLandon J. Fuller if (_size != null) 2313abc551b1SLandon J. Fuller errorx("no more than three property paths may be specified") 2314abc551b1SLandon J. Fuller 231577cb4d3eSLandon J. Fuller _size = array_size(array) 231677cb4d3eSLandon J. Fuller if (_size <= 1) 231777cb4d3eSLandon J. Fuller return 231877cb4d3eSLandon J. Fuller 2319abc551b1SLandon J. Fuller _qsort(array, prop_path0, prop_path1, prop_path2, 0, _size-1) 232077cb4d3eSLandon J. Fuller} 232177cb4d3eSLandon J. Fuller 232277cb4d3eSLandon J. Fullerfunction _qsort_get_key(array, idx, prop_path, _v) { 232377cb4d3eSLandon J. Fuller _v = array_get(array, idx) 232477cb4d3eSLandon J. Fuller 232577cb4d3eSLandon J. Fuller if (prop_path == null) 232677cb4d3eSLandon J. Fuller return (_v) 232777cb4d3eSLandon J. Fuller 232877cb4d3eSLandon J. Fuller return (prop_get_path(_v, prop_path)) 232977cb4d3eSLandon J. Fuller} 233077cb4d3eSLandon J. Fuller 2331abc551b1SLandon J. Fullerfunction _qsort_compare(array, lhs_idx, rhs_val, ppath0, ppath1, ppath2, 2332abc551b1SLandon J. Fuller _lhs_val, _rhs_prop_val) 2333abc551b1SLandon J. Fuller{ 2334abc551b1SLandon J. Fuller _lhs_val = _qsort_get_key(array, lhs_idx, ppath0) 2335abc551b1SLandon J. Fuller if (ppath0 == null) 2336abc551b1SLandon J. Fuller _rhs_prop_val = rhs_val 2337abc551b1SLandon J. Fuller else 2338abc551b1SLandon J. Fuller _rhs_prop_val = prop_get_path(rhs_val, ppath0) 2339abc551b1SLandon J. Fuller 2340abc551b1SLandon J. Fuller if (_lhs_val == _rhs_prop_val && ppath1 != null) { 2341abc551b1SLandon J. Fuller _lhs_val = _qsort_get_key(array, lhs_idx, ppath1) 2342abc551b1SLandon J. Fuller _rhs_prop_val = prop_get_path(rhs_val, ppath1) 2343abc551b1SLandon J. Fuller 2344abc551b1SLandon J. Fuller if (_lhs_val == _rhs_prop_val && ppath2 != null) { 2345abc551b1SLandon J. Fuller _lhs_val = _qsort_get_key(array, lhs_idx, ppath2) 2346abc551b1SLandon J. Fuller _rhs_prop_val = prop_get_path(rhs_val, ppath2) 2347abc551b1SLandon J. Fuller } 2348abc551b1SLandon J. Fuller } 2349abc551b1SLandon J. Fuller 2350abc551b1SLandon J. Fuller if (_lhs_val < _rhs_prop_val) 2351abc551b1SLandon J. Fuller return (-1) 2352abc551b1SLandon J. Fuller else if (_lhs_val > _rhs_prop_val) 2353abc551b1SLandon J. Fuller return (1) 2354abc551b1SLandon J. Fuller else 2355abc551b1SLandon J. Fuller return (0) 2356abc551b1SLandon J. Fuller} 2357abc551b1SLandon J. Fuller 2358abc551b1SLandon J. Fullerfunction _qsort(array, ppath0, ppath1, ppath2, first, last, _qpivot, 2359abc551b1SLandon J. Fuller _qleft, _qleft_val, _qright, _qright_val) 2360e83ce340SAdrian Chadd{ 2361e83ce340SAdrian Chadd if (first >= last) 2362e83ce340SAdrian Chadd return 2363e83ce340SAdrian Chadd 2364e83ce340SAdrian Chadd # select pivot element 2365e83ce340SAdrian Chadd _qpivot = int(first + int((last-first+1) * rand())) 2366e83ce340SAdrian Chadd _qleft = first 2367e83ce340SAdrian Chadd _qright = last 2368e83ce340SAdrian Chadd 2369abc551b1SLandon J. Fuller _qpivot_val = array_get(array, _qpivot) 2370e83ce340SAdrian Chadd 2371e83ce340SAdrian Chadd # partition 2372e83ce340SAdrian Chadd while (_qleft <= _qright) { 2373abc551b1SLandon J. Fuller while (_qsort_compare(array, _qleft, _qpivot_val, ppath0, ppath1, 2374abc551b1SLandon J. Fuller ppath2) < 0) 2375abc551b1SLandon J. Fuller { 2376e83ce340SAdrian Chadd _qleft++ 2377abc551b1SLandon J. Fuller } 2378e83ce340SAdrian Chadd 2379abc551b1SLandon J. Fuller while (_qsort_compare(array, _qright, _qpivot_val, ppath0, ppath1, 2380abc551b1SLandon J. Fuller ppath2) > 0) 2381abc551b1SLandon J. Fuller { 2382e83ce340SAdrian Chadd _qright-- 2383abc551b1SLandon J. Fuller } 2384e83ce340SAdrian Chadd 2385e83ce340SAdrian Chadd # swap 2386e83ce340SAdrian Chadd if (_qleft <= _qright) { 238777cb4d3eSLandon J. Fuller _qleft_val = array_get(array, _qleft) 238877cb4d3eSLandon J. Fuller _qright_val = array_get(array, _qright) 2389e83ce340SAdrian Chadd 239077cb4d3eSLandon J. Fuller array_set(array, _qleft, _qright_val) 239177cb4d3eSLandon J. Fuller array_set(array, _qright, _qleft_val) 2392e83ce340SAdrian Chadd 2393e83ce340SAdrian Chadd _qleft++ 2394e83ce340SAdrian Chadd _qright-- 2395e83ce340SAdrian Chadd } 2396e83ce340SAdrian Chadd } 2397e83ce340SAdrian Chadd 2398e83ce340SAdrian Chadd # sort the partitions 2399abc551b1SLandon J. Fuller _qsort(array, ppath0, ppath1, ppath2, first, _qright) 2400abc551b1SLandon J. Fuller _qsort(array, ppath0, ppath1, ppath2, _qleft, last) 240177cb4d3eSLandon J. Fuller} 240277cb4d3eSLandon J. Fuller 240377cb4d3eSLandon J. Fuller 240477cb4d3eSLandon J. Fuller# 240577cb4d3eSLandon J. Fuller# Join all array values with the given separator 240677cb4d3eSLandon J. Fuller# 240777cb4d3eSLandon J. Fuller# If `prop_path` is non-NULL, the corresponding property path (or property ID) 240877cb4d3eSLandon J. Fuller# will be fetched from each array value and included in the result, rather than 240977cb4d3eSLandon J. Fuller# immediate array value 241077cb4d3eSLandon J. Fuller# 241177cb4d3eSLandon J. Fullerfunction array_join(array, sep, prop_path, _i, _size, _value, _result) { 241277cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 241377cb4d3eSLandon J. Fuller 241477cb4d3eSLandon J. Fuller _result = "" 241577cb4d3eSLandon J. Fuller _size = array_size(array) 241677cb4d3eSLandon J. Fuller for (_i = 0; _i < _size; _i++) { 241777cb4d3eSLandon J. Fuller # Fetch the value (and optionally, a target property) 241877cb4d3eSLandon J. Fuller _value = array_get(array, _i) 241977cb4d3eSLandon J. Fuller if (prop_path != null) 242077cb4d3eSLandon J. Fuller _value = prop_get_path(_value, prop_path) 242177cb4d3eSLandon J. Fuller 242277cb4d3eSLandon J. Fuller if (_i+1 < _size) 242377cb4d3eSLandon J. Fuller _result = _result _value sep 242477cb4d3eSLandon J. Fuller else 242577cb4d3eSLandon J. Fuller _result = _result _value 242677cb4d3eSLandon J. Fuller } 242777cb4d3eSLandon J. Fuller 242877cb4d3eSLandon J. Fuller return (_result) 242977cb4d3eSLandon J. Fuller} 243077cb4d3eSLandon J. Fuller 243177cb4d3eSLandon J. Fuller# Return the first value in the array, or null if empty 243277cb4d3eSLandon J. Fullerfunction array_first(array) { 243377cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 243477cb4d3eSLandon J. Fuller 243577cb4d3eSLandon J. Fuller if (array_size(array) == 0) 243677cb4d3eSLandon J. Fuller return (null) 243777cb4d3eSLandon J. Fuller else 243877cb4d3eSLandon J. Fuller return (array_get(array, 0)) 243977cb4d3eSLandon J. Fuller} 244077cb4d3eSLandon J. Fuller 244177cb4d3eSLandon J. Fuller# Return the last value in the array, or null if empty 244277cb4d3eSLandon J. Fullerfunction array_tail(list, _size) { 244377cb4d3eSLandon J. Fuller obj_assert_class(array, Array) 244477cb4d3eSLandon J. Fuller 244577cb4d3eSLandon J. Fuller _size = array_size(array) 244677cb4d3eSLandon J. Fuller if (_size == 0) 244777cb4d3eSLandon J. Fuller return (null) 244877cb4d3eSLandon J. Fuller else 244977cb4d3eSLandon J. Fuller return (array_get(array, _size-1)) 245077cb4d3eSLandon J. Fuller} 245177cb4d3eSLandon J. Fuller 245277cb4d3eSLandon J. Fuller# Create an empty hash table; this uses the _g_maps array to store arbitrary 245377cb4d3eSLandon J. Fuller# keys/values under the object's property prefix. 245477cb4d3eSLandon J. Fullerfunction map_new(_obj) { 245577cb4d3eSLandon J. Fuller _obj = obj_new(Map) 245677cb4d3eSLandon J. Fuller return (_obj) 245777cb4d3eSLandon J. Fuller} 245877cb4d3eSLandon J. Fuller 245977cb4d3eSLandon J. Fuller# Add `key` with `value` to `map` 246077cb4d3eSLandon J. Fullerfunction map_set(map, key, value) { 246177cb4d3eSLandon J. Fuller obj_assert_class(map, Map) 246277cb4d3eSLandon J. Fuller _g_maps[map,OBJ_PROP,key] = value 246377cb4d3eSLandon J. Fuller} 246477cb4d3eSLandon J. Fuller 246577cb4d3eSLandon J. Fuller# Remove `key` from the map 246677cb4d3eSLandon J. Fullerfunction map_remove(map, key) { 246777cb4d3eSLandon J. Fuller obj_assert_class(map, Map) 246877cb4d3eSLandon J. Fuller delete _g_maps[map,OBJ_PROP,key] 246977cb4d3eSLandon J. Fuller} 247077cb4d3eSLandon J. Fuller 247177cb4d3eSLandon J. Fuller# Return true if `key` is found in `map`, false otherwise 247277cb4d3eSLandon J. Fullerfunction map_contains(map, key) { 247377cb4d3eSLandon J. Fuller obj_assert_class(map, Map) 247477cb4d3eSLandon J. Fuller return ((map,OBJ_PROP,key) in _g_maps) 247577cb4d3eSLandon J. Fuller} 247677cb4d3eSLandon J. Fuller 247777cb4d3eSLandon J. Fuller# Fetch the value of `key` from the map. Will throw an error if the 247877cb4d3eSLandon J. Fuller# key does not exist 247977cb4d3eSLandon J. Fullerfunction map_get(map, key) { 248077cb4d3eSLandon J. Fuller obj_assert_class(map, Map) 248177cb4d3eSLandon J. Fuller return _g_maps[map,OBJ_PROP,key] 248277cb4d3eSLandon J. Fuller} 248377cb4d3eSLandon J. Fuller 248477cb4d3eSLandon J. Fuller# Create and return a new list containing all defined values in `map` 248577cb4d3eSLandon J. Fullerfunction map_to_array(map, _key, _prefix, _values) { 248677cb4d3eSLandon J. Fuller obj_assert_class(map, Map) 248777cb4d3eSLandon J. Fuller 248877cb4d3eSLandon J. Fuller _values = array_new() 248977cb4d3eSLandon J. Fuller _prefix = "^" map SUBSEP OBJ_PROP SUBSEP 249077cb4d3eSLandon J. Fuller for (_key in _g_maps) { 249177cb4d3eSLandon J. Fuller if (!match(_key, _prefix)) 249277cb4d3eSLandon J. Fuller continue 249377cb4d3eSLandon J. Fuller 249477cb4d3eSLandon J. Fuller array_append(_values, _g_maps[_key]) 249577cb4d3eSLandon J. Fuller } 249677cb4d3eSLandon J. Fuller 249777cb4d3eSLandon J. Fuller return (_values) 249877cb4d3eSLandon J. Fuller} 249977cb4d3eSLandon J. Fuller 250077cb4d3eSLandon J. Fuller# Create a new Type instance 250177cb4d3eSLandon J. Fullerfunction type_new(name, width, signed, constant, array_constant, fmt, mask, 250277cb4d3eSLandon J. Fuller constant_value, array_constant_value, _obj) 250377cb4d3eSLandon J. Fuller{ 250477cb4d3eSLandon J. Fuller obj_assert_class(fmt, Fmt) 250577cb4d3eSLandon J. Fuller 250677cb4d3eSLandon J. Fuller _obj = obj_new(Type) 250777cb4d3eSLandon J. Fuller set(_obj, p_name, name) 250877cb4d3eSLandon J. Fuller set(_obj, p_width, width) 250977cb4d3eSLandon J. Fuller set(_obj, p_signed, signed) 251077cb4d3eSLandon J. Fuller set(_obj, p_const, constant) 251177cb4d3eSLandon J. Fuller set(_obj, p_const_val, constant_value) 251277cb4d3eSLandon J. Fuller set(_obj, p_array_const, array_constant) 251377cb4d3eSLandon J. Fuller set(_obj, p_array_const_val, array_constant_value) 251477cb4d3eSLandon J. Fuller set(_obj, p_default_fmt, fmt) 251577cb4d3eSLandon J. Fuller set(_obj, p_mask, mask) 251677cb4d3eSLandon J. Fuller 251777cb4d3eSLandon J. Fuller return (_obj) 251877cb4d3eSLandon J. Fuller} 251977cb4d3eSLandon J. Fuller 252077cb4d3eSLandon J. Fuller# Return true if two types are equal 252177cb4d3eSLandon J. Fullerfunction type_equal(lhs, rhs) { 252277cb4d3eSLandon J. Fuller # Simple case 252377cb4d3eSLandon J. Fuller if (lhs == rhs) 252477cb4d3eSLandon J. Fuller return (1) 252577cb4d3eSLandon J. Fuller 252677cb4d3eSLandon J. Fuller # Must share a common class 252777cb4d3eSLandon J. Fuller if (obj_get_class(lhs) != obj_get_class(rhs)) 252877cb4d3eSLandon J. Fuller return (0) 252977cb4d3eSLandon J. Fuller 253077cb4d3eSLandon J. Fuller # Handle ArrayType equality 253177cb4d3eSLandon J. Fuller if (obj_is_instanceof(lhs, ArrayType)) { 253277cb4d3eSLandon J. Fuller # Size must be equal 253377cb4d3eSLandon J. Fuller if (get(lhs, p_count) != get(rhs, p_count)) 253477cb4d3eSLandon J. Fuller return (0) 253577cb4d3eSLandon J. Fuller 253677cb4d3eSLandon J. Fuller # The base types must be equal 253777cb4d3eSLandon J. Fuller return (type_equal(type_get_base(lhs), type_get_base(rhs))) 253877cb4d3eSLandon J. Fuller } 253977cb4d3eSLandon J. Fuller 254077cb4d3eSLandon J. Fuller # Handle Type equality -- we just check for trivial identity 254177cb4d3eSLandon J. Fuller # equality of all members 254277cb4d3eSLandon J. Fuller obj_assert_class(lhs, Type) 254377cb4d3eSLandon J. Fuller return (obj_trivially_equal(lhs, rhs)) 254477cb4d3eSLandon J. Fuller} 254577cb4d3eSLandon J. Fuller 254677cb4d3eSLandon J. Fuller# Return the type's default value mask. If the type is an array type, 254777cb4d3eSLandon J. Fuller# the default mask of the base type will be returned. 254877cb4d3eSLandon J. Fullerfunction type_get_default_mask(type) { 254977cb4d3eSLandon J. Fuller if (obj_is_instanceof(type, ArrayType)) 255077cb4d3eSLandon J. Fuller return (type_get_default_mask(type_get_base(type))) 255177cb4d3eSLandon J. Fuller 255277cb4d3eSLandon J. Fuller obj_assert_class(type, Type) 255377cb4d3eSLandon J. Fuller return (get(type, p_mask)) 255477cb4d3eSLandon J. Fuller} 255577cb4d3eSLandon J. Fuller 255677cb4d3eSLandon J. Fuller# Return the type's C constant representation 255777cb4d3eSLandon J. Fullerfunction type_get_const(type) { 255877cb4d3eSLandon J. Fuller if (obj_is_instanceof(type, ArrayType)) 255977cb4d3eSLandon J. Fuller return (get(type_get_base(type), p_array_const)) 256077cb4d3eSLandon J. Fuller 256177cb4d3eSLandon J. Fuller obj_assert_class(type, Type) 256277cb4d3eSLandon J. Fuller return (get(type, p_const)) 256377cb4d3eSLandon J. Fuller} 256477cb4d3eSLandon J. Fuller 256577cb4d3eSLandon J. Fuller# Return the type's C constant integer value 256677cb4d3eSLandon J. Fullerfunction type_get_const_val(type) { 256777cb4d3eSLandon J. Fuller if (obj_is_instanceof(type, ArrayType)) 256877cb4d3eSLandon J. Fuller return (get(type_get_base(type), p_array_const_val)) 256977cb4d3eSLandon J. Fuller 257077cb4d3eSLandon J. Fuller obj_assert_class(type, Type) 257177cb4d3eSLandon J. Fuller return (get(type, p_const_val)) 257277cb4d3eSLandon J. Fuller} 257377cb4d3eSLandon J. Fuller 257477cb4d3eSLandon J. Fuller# Return an array type's element count, or 1 if the type is not 257577cb4d3eSLandon J. Fuller# an array type 257677cb4d3eSLandon J. Fullerfunction type_get_nelem(type) { 257777cb4d3eSLandon J. Fuller if (obj_is_instanceof(type, ArrayType)) 257877cb4d3eSLandon J. Fuller return (get(type, p_count)) 257977cb4d3eSLandon J. Fuller 258077cb4d3eSLandon J. Fuller obj_assert_class(type, Type) 258177cb4d3eSLandon J. Fuller return (1) 258277cb4d3eSLandon J. Fuller} 258377cb4d3eSLandon J. Fuller 258477cb4d3eSLandon J. Fuller# Return the base type for a given type instance. 258577cb4d3eSLandon J. Fullerfunction type_get_base(type) { 258677cb4d3eSLandon J. Fuller if (obj_is_instanceof(type, ArrayType)) 258777cb4d3eSLandon J. Fuller return (type_get_base(get(type, p_type))) 258877cb4d3eSLandon J. Fuller 258977cb4d3eSLandon J. Fuller obj_assert_class(type, Type) 259077cb4d3eSLandon J. Fuller return (type) 259177cb4d3eSLandon J. Fuller} 259277cb4d3eSLandon J. Fuller 259377cb4d3eSLandon J. Fuller# Return the default fmt for a given type instance 2594c283839dSLandon J. Fullerfunction type_get_default_fmt(type, _base, _fmt, _array_fmt) { 259577cb4d3eSLandon J. Fuller _base = type_get_base(type) 2596c283839dSLandon J. Fuller _fmt = get(_base, p_default_fmt) 2597c283839dSLandon J. Fuller 2598c283839dSLandon J. Fuller if (obj_is_instanceof(type, ArrayType)) { 2599c283839dSLandon J. Fuller _array_fmt = get(_fmt, p_array_fmt) 2600c283839dSLandon J. Fuller if (_array_fmt != null) 2601c283839dSLandon J. Fuller _fmt = _array_fmt 2602c283839dSLandon J. Fuller } 2603c283839dSLandon J. Fuller 2604c283839dSLandon J. Fuller return (_fmt) 260577cb4d3eSLandon J. Fuller} 260677cb4d3eSLandon J. Fuller 260777cb4d3eSLandon J. Fuller# Return a string representation of the given type 260877cb4d3eSLandon J. Fullerfunction type_to_string(type, _base_type) { 260977cb4d3eSLandon J. Fuller if (obj_is_instanceof(type, ArrayType)) { 261077cb4d3eSLandon J. Fuller _base_type = type_get_base(type) 261177cb4d3eSLandon J. Fuller return (type_to_string(_base_type) "[" get(type, p_count) "]") 261277cb4d3eSLandon J. Fuller } 261377cb4d3eSLandon J. Fuller return get(type, p_name) 261477cb4d3eSLandon J. Fuller} 261577cb4d3eSLandon J. Fuller 261677cb4d3eSLandon J. Fuller# Return true if type `rhs` is can be coerced to type `lhs` without data 261777cb4d3eSLandon J. Fuller# loss 261877cb4d3eSLandon J. Fullerfunction type_can_represent(lhs, rhs) { 261977cb4d3eSLandon J. Fuller # Must be of the same class (Type or ArrayType) 262077cb4d3eSLandon J. Fuller if (obj_get_class(lhs) != obj_get_class(rhs)) 262177cb4d3eSLandon J. Fuller return (0) 262277cb4d3eSLandon J. Fuller 262377cb4d3eSLandon J. Fuller if (obj_is_instanceof(lhs, ArrayType)) { 262477cb4d3eSLandon J. Fuller # The base types must have a representable relationship 262577cb4d3eSLandon J. Fuller if (!type_can_represent(type_get_base(lhs), type_get_base(rhs))) 262677cb4d3eSLandon J. Fuller return (0) 262777cb4d3eSLandon J. Fuller 262877cb4d3eSLandon J. Fuller # The lhs type must be able to represent -at least- as 262977cb4d3eSLandon J. Fuller # many elements as the RHS type 263077cb4d3eSLandon J. Fuller if (get(lhs, p_count) < get(rhs, p_count)) 263177cb4d3eSLandon J. Fuller return (0) 263277cb4d3eSLandon J. Fuller 263377cb4d3eSLandon J. Fuller return (1) 263477cb4d3eSLandon J. Fuller } 263577cb4d3eSLandon J. Fuller 263677cb4d3eSLandon J. Fuller # A signed type could represent the full range of a smaller unsigned 263777cb4d3eSLandon J. Fuller # type, but we don't bother; the two should agree when used in a SROM 263877cb4d3eSLandon J. Fuller # layout. Instead simply assert that both are signed or unsigned. 263977cb4d3eSLandon J. Fuller if (get(lhs, p_signed) != get(rhs, p_signed)) 264077cb4d3eSLandon J. Fuller return (0) 264177cb4d3eSLandon J. Fuller 264277cb4d3eSLandon J. Fuller # The `rhs` type must be equal or smaller in width to the `lhs` type 264377cb4d3eSLandon J. Fuller if (get(lhs, p_width) < get(rhs, p_width)) 264477cb4d3eSLandon J. Fuller return (0) 264577cb4d3eSLandon J. Fuller 264677cb4d3eSLandon J. Fuller return (1) 264777cb4d3eSLandon J. Fuller} 264877cb4d3eSLandon J. Fuller 264977cb4d3eSLandon J. Fuller# Create a new ArrayType instance 265077cb4d3eSLandon J. Fullerfunction array_type_new(type, count, _obj) { 265177cb4d3eSLandon J. Fuller _obj = obj_new(ArrayType) 265277cb4d3eSLandon J. Fuller set(_obj, p_type, type) 265377cb4d3eSLandon J. Fuller set(_obj, p_count, count) 265477cb4d3eSLandon J. Fuller 265577cb4d3eSLandon J. Fuller return (_obj) 265677cb4d3eSLandon J. Fuller} 265777cb4d3eSLandon J. Fuller 265877cb4d3eSLandon J. Fuller# 265977cb4d3eSLandon J. Fuller# Parse a type string to either the Type, ArrayType, or null if 266077cb4d3eSLandon J. Fuller# the type is not recognized. 266177cb4d3eSLandon J. Fuller# 266277cb4d3eSLandon J. Fullerfunction parse_type_string(str, _base, _count) { 266377cb4d3eSLandon J. Fuller if (match(str, ARRAY_REGEX"$") > 0) { 266477cb4d3eSLandon J. Fuller # Extract count and base type 266577cb4d3eSLandon J. Fuller _count = substr(str, RSTART+1, RLENGTH-2) 266677cb4d3eSLandon J. Fuller sub(ARRAY_REGEX"$", "", str) 266777cb4d3eSLandon J. Fuller 266877cb4d3eSLandon J. Fuller # Look for base type 266977cb4d3eSLandon J. Fuller if ((_base = type_named(str)) == null) 267077cb4d3eSLandon J. Fuller return (null) 267177cb4d3eSLandon J. Fuller 267277cb4d3eSLandon J. Fuller return (array_type_new(_base, int(_count))) 267377cb4d3eSLandon J. Fuller } else { 267477cb4d3eSLandon J. Fuller return (type_named(str)) 267577cb4d3eSLandon J. Fuller } 267677cb4d3eSLandon J. Fuller} 267777cb4d3eSLandon J. Fuller 267877cb4d3eSLandon J. Fuller# 267977cb4d3eSLandon J. Fuller# Parse a variable name in the form of 'name' or 'name[len]', returning 268077cb4d3eSLandon J. Fuller# either the provided base_type if no array specifiers are found, or 268177cb4d3eSLandon J. Fuller# the fully parsed ArrayType. 268277cb4d3eSLandon J. Fuller# 268377cb4d3eSLandon J. Fullerfunction parse_array_type_specifier(str, base_type, _count) { 268477cb4d3eSLandon J. Fuller if (match(str, ARRAY_REGEX"$") > 0) { 268577cb4d3eSLandon J. Fuller # Extract count 268677cb4d3eSLandon J. Fuller _count = substr(str, RSTART+1, RLENGTH-2) 268777cb4d3eSLandon J. Fuller return (array_type_new(base_type, int(_count))) 268877cb4d3eSLandon J. Fuller } else { 268977cb4d3eSLandon J. Fuller return (base_type) 269077cb4d3eSLandon J. Fuller } 269177cb4d3eSLandon J. Fuller} 269277cb4d3eSLandon J. Fuller 269377cb4d3eSLandon J. Fuller# Return the type constant for `name`, if any 269477cb4d3eSLandon J. Fullerfunction type_named(name, _n, _type) { 269577cb4d3eSLandon J. Fuller if (name == null) 269677cb4d3eSLandon J. Fuller errorx("called type_named() with null name") 269777cb4d3eSLandon J. Fuller 269877cb4d3eSLandon J. Fuller if (map_contains(BaseTypes, name)) 269977cb4d3eSLandon J. Fuller return (map_get(BaseTypes, name)) 270077cb4d3eSLandon J. Fuller 270177cb4d3eSLandon J. Fuller return (null) 270277cb4d3eSLandon J. Fuller} 270377cb4d3eSLandon J. Fuller 270477cb4d3eSLandon J. Fuller# Create a new Fmt instance 2705c283839dSLandon J. Fullerfunction fmt_new(name, symbol, array_fmt, _obj) { 270677cb4d3eSLandon J. Fuller _obj = obj_new(Fmt) 270777cb4d3eSLandon J. Fuller set(_obj, p_name, name) 270877cb4d3eSLandon J. Fuller set(_obj, p_symbol, symbol) 270977cb4d3eSLandon J. Fuller 2710c283839dSLandon J. Fuller if (array_fmt != null) 2711c283839dSLandon J. Fuller set(_obj, p_array_fmt, array_fmt) 2712c283839dSLandon J. Fuller 271377cb4d3eSLandon J. Fuller return (_obj) 271477cb4d3eSLandon J. Fuller} 271577cb4d3eSLandon J. Fuller 271677cb4d3eSLandon J. Fuller 271777cb4d3eSLandon J. Fuller# Return the Fmt constant for `name`, if any 271877cb4d3eSLandon J. Fullerfunction fmt_named(name, _n, _fmt) { 271977cb4d3eSLandon J. Fuller if (map_contains(ValueFormats, name)) 272077cb4d3eSLandon J. Fuller return (map_get(ValueFormats, name)) 272177cb4d3eSLandon J. Fuller 272277cb4d3eSLandon J. Fuller return (null) 272377cb4d3eSLandon J. Fuller} 272477cb4d3eSLandon J. Fuller 272577cb4d3eSLandon J. Fuller# Create a new VFlag instance 272677cb4d3eSLandon J. Fullerfunction vflag_new(name, constant, _obj) { 272777cb4d3eSLandon J. Fuller _obj = obj_new(VFlag) 272877cb4d3eSLandon J. Fuller set(_obj, p_name, name) 272977cb4d3eSLandon J. Fuller set(_obj, p_const, constant) 273077cb4d3eSLandon J. Fuller 273177cb4d3eSLandon J. Fuller return (_obj) 273277cb4d3eSLandon J. Fuller} 273377cb4d3eSLandon J. Fuller 273477cb4d3eSLandon J. Fuller# Create a new StringConstant AST node 273577cb4d3eSLandon J. Fullerfunction stringconstant_new(value, continued, _obj) { 273677cb4d3eSLandon J. Fuller _obj = obj_new(StringConstant) 273777cb4d3eSLandon J. Fuller set(_obj, p_value, value) 273877cb4d3eSLandon J. Fuller set(_obj, p_continued, continued) 273977cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 274077cb4d3eSLandon J. Fuller 274177cb4d3eSLandon J. Fuller return (_obj) 274277cb4d3eSLandon J. Fuller} 274377cb4d3eSLandon J. Fuller 274477cb4d3eSLandon J. Fuller# Create an empty StringConstant AST node to which additional lines 274577cb4d3eSLandon J. Fuller# may be appended 274677cb4d3eSLandon J. Fullerfunction stringconstant_empty(_obj) { 274777cb4d3eSLandon J. Fuller return (stringconstant_new("", 1)) 274877cb4d3eSLandon J. Fuller} 274977cb4d3eSLandon J. Fuller 275077cb4d3eSLandon J. Fuller# Parse an input string and return a new string constant 275177cb4d3eSLandon J. Fuller# instance 275277cb4d3eSLandon J. Fullerfunction stringconstant_parse_line(line, _obj) { 275377cb4d3eSLandon J. Fuller _obj = stringconstant_empty() 275477cb4d3eSLandon J. Fuller stringconstant_append_line(_obj, line) 275577cb4d3eSLandon J. Fuller return (_obj) 275677cb4d3eSLandon J. Fuller} 275777cb4d3eSLandon J. Fuller 275877cb4d3eSLandon J. Fuller# Parse and apend an additional line to this string constant 275977cb4d3eSLandon J. Fullerfunction stringconstant_append_line(str, line, _cont, _strbuf, _regex, _eol) { 276077cb4d3eSLandon J. Fuller obj_assert_class(str, StringConstant) 276177cb4d3eSLandon J. Fuller 276277cb4d3eSLandon J. Fuller # Must be marked for continuation 276377cb4d3eSLandon J. Fuller if (!get(str, p_continued)) { 276477cb4d3eSLandon J. Fuller errorx("can't append to non-continuation string '" \ 276577cb4d3eSLandon J. Fuller get(str, p_value) "'") 276677cb4d3eSLandon J. Fuller } 276777cb4d3eSLandon J. Fuller 276877cb4d3eSLandon J. Fuller _strbuf = get(str, p_value) 276977cb4d3eSLandon J. Fuller 277077cb4d3eSLandon J. Fuller # If start of string, look for (and remove) initial double quote 277177cb4d3eSLandon J. Fuller if (_strbuf == null) { 277277cb4d3eSLandon J. Fuller _regex = "^[ \t]*\"" 277377cb4d3eSLandon J. Fuller if (!sub(_regex, "", line)) { 277477cb4d3eSLandon J. Fuller error("expected quoted string") 277577cb4d3eSLandon J. Fuller } 277677cb4d3eSLandon J. Fuller } 277777cb4d3eSLandon J. Fuller 277877cb4d3eSLandon J. Fuller # Look for a terminating double quote 277977cb4d3eSLandon J. Fuller _regex = "([^\"\\\\]*(\\\\.[^\"\\\\]*)*)\"" 278077cb4d3eSLandon J. Fuller 278177cb4d3eSLandon J. Fuller _eol = match(line, _regex) 278277cb4d3eSLandon J. Fuller if (_eol > 0) { 278377cb4d3eSLandon J. Fuller # Drop everything following the terminating quote 278477cb4d3eSLandon J. Fuller line = substr(line, 1, RLENGTH-1) 278577cb4d3eSLandon J. Fuller _cont = 0 278677cb4d3eSLandon J. Fuller } else { 278777cb4d3eSLandon J. Fuller # No terminating quote found, continues on next line 278877cb4d3eSLandon J. Fuller _cont = 1 278977cb4d3eSLandon J. Fuller } 279077cb4d3eSLandon J. Fuller 279177cb4d3eSLandon J. Fuller # Trim leading and trailing whitespace 279277cb4d3eSLandon J. Fuller sub(/(^[ \t]+|[ \t]+$)/, "", line) 279377cb4d3eSLandon J. Fuller 279477cb4d3eSLandon J. Fuller # Append to existing buffer 279577cb4d3eSLandon J. Fuller if ((_strbuf = get(str, p_value)) == NULL) 279677cb4d3eSLandon J. Fuller set(str, p_value, line) 279777cb4d3eSLandon J. Fuller else 279877cb4d3eSLandon J. Fuller set(str, p_value, _strbuf " " line) 279977cb4d3eSLandon J. Fuller 280077cb4d3eSLandon J. Fuller # Update line continuation setting 280177cb4d3eSLandon J. Fuller set(str, p_continued, _cont) 280277cb4d3eSLandon J. Fuller} 280377cb4d3eSLandon J. Fuller 280477cb4d3eSLandon J. Fuller# Create a new RevRange instance 280577cb4d3eSLandon J. Fullerfunction revrange_new(start, end, _obj) { 280677cb4d3eSLandon J. Fuller _obj = obj_new(RevRange) 280777cb4d3eSLandon J. Fuller set(_obj, p_start, start) 280877cb4d3eSLandon J. Fuller set(_obj, p_end, end) 280977cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 281077cb4d3eSLandon J. Fuller 281177cb4d3eSLandon J. Fuller return (_obj) 281277cb4d3eSLandon J. Fuller} 281377cb4d3eSLandon J. Fuller 281477cb4d3eSLandon J. Fuller# Return true if the two revision ranges are equal 281577cb4d3eSLandon J. Fullerfunction revrange_equal(lhs, rhs) { 281677cb4d3eSLandon J. Fuller if (get(lhs, p_start) != get(rhs, p_start)) 281777cb4d3eSLandon J. Fuller return (0) 281877cb4d3eSLandon J. Fuller 281977cb4d3eSLandon J. Fuller if (get(lhs, p_end) != get(rhs, p_end)) 282077cb4d3eSLandon J. Fuller return (0) 282177cb4d3eSLandon J. Fuller 282277cb4d3eSLandon J. Fuller return (1) 282377cb4d3eSLandon J. Fuller} 282477cb4d3eSLandon J. Fuller 282577cb4d3eSLandon J. Fuller# Return true if the requested rev is covered by revrange, false otherwise 282677cb4d3eSLandon J. Fullerfunction revrange_contains(range, rev) { 282777cb4d3eSLandon J. Fuller obj_assert_class(range, RevRange) 282877cb4d3eSLandon J. Fuller 282977cb4d3eSLandon J. Fuller if (rev < get(range, p_start)) 283077cb4d3eSLandon J. Fuller return (0) 283177cb4d3eSLandon J. Fuller else if (rev > get(range, p_end)) { 283277cb4d3eSLandon J. Fuller return (0) 283377cb4d3eSLandon J. Fuller } else { 283477cb4d3eSLandon J. Fuller return (1) 283577cb4d3eSLandon J. Fuller } 283677cb4d3eSLandon J. Fuller} 283777cb4d3eSLandon J. Fuller 283877cb4d3eSLandon J. Fuller# 283977cb4d3eSLandon J. Fuller# Return a string representation of the given revision range 284077cb4d3eSLandon J. Fuller# 284177cb4d3eSLandon J. Fullerfunction revrange_to_string(revs, _start, _end) { 284277cb4d3eSLandon J. Fuller obj_assert_class(revs, RevRange) 284377cb4d3eSLandon J. Fuller 284477cb4d3eSLandon J. Fuller _start = get(revs, p_start) 284577cb4d3eSLandon J. Fuller _end = get(revs, p_end) 284677cb4d3eSLandon J. Fuller 284777cb4d3eSLandon J. Fuller if (_start == 0) 284877cb4d3eSLandon J. Fuller return ("<= " _end) 284977cb4d3eSLandon J. Fuller else if (_end == REV_MAX) 285077cb4d3eSLandon J. Fuller return (">= " _start) 285177cb4d3eSLandon J. Fuller else 285277cb4d3eSLandon J. Fuller return (_start "-" _end) 285377cb4d3eSLandon J. Fuller} 285477cb4d3eSLandon J. Fuller 285577cb4d3eSLandon J. Fuller# Create a new VarGroup instance 285677cb4d3eSLandon J. Fullerfunction var_group_new(name, _obj) { 285777cb4d3eSLandon J. Fuller _obj = obj_new(VarGroup) 285877cb4d3eSLandon J. Fuller set(_obj, p_name, name) 285977cb4d3eSLandon J. Fuller set(_obj, p_vars, array_new()) 286077cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 286177cb4d3eSLandon J. Fuller 286277cb4d3eSLandon J. Fuller return (_obj) 286377cb4d3eSLandon J. Fuller} 286477cb4d3eSLandon J. Fuller 286577cb4d3eSLandon J. Fuller# Create a new NVRAM instance 286677cb4d3eSLandon J. Fullerfunction nvram_new(_obj, _vars, _v) { 286777cb4d3eSLandon J. Fuller _obj = obj_new(NVRAM) 286877cb4d3eSLandon J. Fuller _vars = array_new() 286977cb4d3eSLandon J. Fuller set(_obj, p_vars, _vars) 287077cb4d3eSLandon J. Fuller set(_obj, p_var_groups, array_new()) 287177cb4d3eSLandon J. Fuller set(_obj, p_srom_layouts, array_new()) 287277cb4d3eSLandon J. Fuller set(_obj, p_srom_table, map_new()) 287377cb4d3eSLandon J. Fuller 287477cb4d3eSLandon J. Fuller # 287577cb4d3eSLandon J. Fuller # Register our implicit variable definitions 287677cb4d3eSLandon J. Fuller # 287777cb4d3eSLandon J. Fuller 287877cb4d3eSLandon J. Fuller # SROM signature offset 287977cb4d3eSLandon J. Fuller _v = var_new(VAccessInternal, "<sromsig>", UInt16) 288077cb4d3eSLandon J. Fuller array_append(_vars, _v) 288177cb4d3eSLandon J. Fuller _g_var_names[get(_v, p_name)] = _v 288277cb4d3eSLandon J. Fuller 288377cb4d3eSLandon J. Fuller # SROM CRC8 offset 288477cb4d3eSLandon J. Fuller _v = var_new(VAccessInternal, "<sromcrc>", UInt8) 288577cb4d3eSLandon J. Fuller array_append(_vars, _v) 288677cb4d3eSLandon J. Fuller _g_var_names[get(_v, p_name)] = _v 288777cb4d3eSLandon J. Fuller 288877cb4d3eSLandon J. Fuller return (_obj) 288977cb4d3eSLandon J. Fuller} 289077cb4d3eSLandon J. Fuller 289177cb4d3eSLandon J. Fuller# Register a new SROM layout instance 289277cb4d3eSLandon J. Fuller# An error will be thrown if the layout overlaps any revisions covered 289377cb4d3eSLandon J. Fuller# by an existing instance. 289477cb4d3eSLandon J. Fullerfunction nvram_add_srom_layout(nvram, layout, _table, _revs, _start, _end, _i) { 289577cb4d3eSLandon J. Fuller obj_assert_class(nvram, NVRAM) 289677cb4d3eSLandon J. Fuller obj_assert_class(layout, SromLayout) 289777cb4d3eSLandon J. Fuller 289877cb4d3eSLandon J. Fuller # revision:layout hash table 289977cb4d3eSLandon J. Fuller _table = get(nvram, p_srom_table) 290077cb4d3eSLandon J. Fuller 290177cb4d3eSLandon J. Fuller # register the layout's revisions 290277cb4d3eSLandon J. Fuller _revs = get(layout, p_revisions) 290377cb4d3eSLandon J. Fuller _start = get(_revs, p_start) 290477cb4d3eSLandon J. Fuller _end = get(_revs, p_end) 290577cb4d3eSLandon J. Fuller 290677cb4d3eSLandon J. Fuller for (_i = _start; _i <= _end; _i++) { 290777cb4d3eSLandon J. Fuller if (map_contains(_table, _i)) { 290877cb4d3eSLandon J. Fuller error("SROM layout redeclares layout for revision '" \ 290977cb4d3eSLandon J. Fuller _i "' (originally declared on line " \ 291077cb4d3eSLandon J. Fuller get(map_get(_table, _i), p_line) ")") 291177cb4d3eSLandon J. Fuller } 291277cb4d3eSLandon J. Fuller 291377cb4d3eSLandon J. Fuller map_set(_table, _i, layout) 291477cb4d3eSLandon J. Fuller } 291577cb4d3eSLandon J. Fuller 291677cb4d3eSLandon J. Fuller # append to srom_layouts 291777cb4d3eSLandon J. Fuller array_append(get(nvram, p_srom_layouts), layout) 291877cb4d3eSLandon J. Fuller} 291977cb4d3eSLandon J. Fuller 292077cb4d3eSLandon J. Fuller# Return the first SROM layout registered for a given SROM revision, 292177cb4d3eSLandon J. Fuller# or null if no matching layout is found 292277cb4d3eSLandon J. Fullerfunction nvram_get_srom_layout(nvram, revision, _layouts, _nlayouts, _layout, 292377cb4d3eSLandon J. Fuller _i) 292477cb4d3eSLandon J. Fuller{ 292577cb4d3eSLandon J. Fuller obj_assert_class(nvram, NVRAM) 292677cb4d3eSLandon J. Fuller 292777cb4d3eSLandon J. Fuller _layouts = get(nvram, p_srom_layouts) 292877cb4d3eSLandon J. Fuller _nlayouts = array_size(_layouts) 292977cb4d3eSLandon J. Fuller for (_i = 0; _i < _nlayouts; _i++) { 293077cb4d3eSLandon J. Fuller _layout = array_get(_layouts, _i) 293177cb4d3eSLandon J. Fuller 293277cb4d3eSLandon J. Fuller if (srom_layout_has_rev(_layout, revision)) 293377cb4d3eSLandon J. Fuller return (_layout) 293477cb4d3eSLandon J. Fuller } 293577cb4d3eSLandon J. Fuller 293677cb4d3eSLandon J. Fuller # Not found 293777cb4d3eSLandon J. Fuller return (null) 293877cb4d3eSLandon J. Fuller} 293977cb4d3eSLandon J. Fuller 294077cb4d3eSLandon J. Fuller# Create a new Var instance 294177cb4d3eSLandon J. Fullerfunction var_new(access, name, type, _obj) { 294277cb4d3eSLandon J. Fuller obj_assert_class(access, VAccess) 294377cb4d3eSLandon J. Fuller 294477cb4d3eSLandon J. Fuller # Validate the variable identifier 294577cb4d3eSLandon J. Fuller # 294677cb4d3eSLandon J. Fuller # The access modifier dictates the permitted identifier format. 294777cb4d3eSLandon J. Fuller # VAccessInternal: <ident> 294877cb4d3eSLandon J. Fuller # VAccess(Public|Private): ident 294977cb4d3eSLandon J. Fuller if (access != VAccessInternal && name ~ SVAR_IDENT_REGEX) { 295077cb4d3eSLandon J. Fuller error("invalid identifier '"name"'; did you mean to " \ 295177cb4d3eSLandon J. Fuller "mark this variable as internal?") 295277cb4d3eSLandon J. Fuller } else if (access == VAccessInternal) { 295377cb4d3eSLandon J. Fuller if (name !~ SVAR_IDENT_REGEX) 295477cb4d3eSLandon J. Fuller error("invalid identifier '"name"' for internal " \ 295577cb4d3eSLandon J. Fuller "variable; did you mean '<" name ">'?") 295677cb4d3eSLandon J. Fuller } else if (name !~ VAR_IDENT_REGEX) { 295777cb4d3eSLandon J. Fuller error("invalid identifier '"name"'") 295877cb4d3eSLandon J. Fuller } 295977cb4d3eSLandon J. Fuller 296077cb4d3eSLandon J. Fuller _obj = obj_new(Var) 296177cb4d3eSLandon J. Fuller set(_obj, p_access, access) 296277cb4d3eSLandon J. Fuller set(_obj, p_name, name) 296377cb4d3eSLandon J. Fuller set(_obj, p_type, type) 296477cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 296577cb4d3eSLandon J. Fuller 296677cb4d3eSLandon J. Fuller return (_obj) 296777cb4d3eSLandon J. Fuller} 296877cb4d3eSLandon J. Fuller 296977cb4d3eSLandon J. Fuller# Return true if var is internal-only, and should not be included 297077cb4d3eSLandon J. Fuller# in any output (e.g. has an access specifier of VAccessInternal). 297177cb4d3eSLandon J. Fullerfunction var_is_internal(var) { 297277cb4d3eSLandon J. Fuller return (get(var, p_access) == VAccessInternal) 297377cb4d3eSLandon J. Fuller} 297477cb4d3eSLandon J. Fuller 297577cb4d3eSLandon J. Fuller# Return true if `var` has an array type 297677cb4d3eSLandon J. Fullerfunction var_has_array_type(var, _vtype) { 297777cb4d3eSLandon J. Fuller obj_assert_class(var, Var) 297877cb4d3eSLandon J. Fuller _vtype = get(var, p_type) 297977cb4d3eSLandon J. Fuller return (obj_is_instanceof(_vtype, ArrayType)) 298077cb4d3eSLandon J. Fuller} 298177cb4d3eSLandon J. Fuller 298277cb4d3eSLandon J. Fuller# Return the number of array elements defined by this variable's type, 298377cb4d3eSLandon J. Fuller# or 1 if the variable does not have an array type. 298477cb4d3eSLandon J. Fullerfunction var_get_array_len(var) { 298577cb4d3eSLandon J. Fuller obj_assert_class(var, Var) 298677cb4d3eSLandon J. Fuller return (type_get_nelem(get(var, p_type))) 298777cb4d3eSLandon J. Fuller} 298877cb4d3eSLandon J. Fuller 298977cb4d3eSLandon J. Fuller# Return the fmt for var. If not explicitly set on var, will return then 299077cb4d3eSLandon J. Fuller# return of calling type_get_default_fmt() with the variable's type 299177cb4d3eSLandon J. Fullerfunction var_get_fmt(var, _fmt) { 299277cb4d3eSLandon J. Fuller obj_assert_class(var, Var) 299377cb4d3eSLandon J. Fuller 299477cb4d3eSLandon J. Fuller # If defined on var, return it 299577cb4d3eSLandon J. Fuller if ((_fmt = get(var, p_fmt)) != null) 299677cb4d3eSLandon J. Fuller return (_fmt) 299777cb4d3eSLandon J. Fuller 299877cb4d3eSLandon J. Fuller # Fall back on the type's default 299977cb4d3eSLandon J. Fuller return (type_get_default_fmt(get(var, p_type))) 300077cb4d3eSLandon J. Fuller} 300177cb4d3eSLandon J. Fuller 300277cb4d3eSLandon J. Fuller# Return a new MacroDefine instance for the given variable, macro type, 300377cb4d3eSLandon J. Fuller# and value 300477cb4d3eSLandon J. Fullerfunction var_get_macro(var, macro_type, value, _macro) { 300577cb4d3eSLandon J. Fuller obj_assert_class(var, Var) 300677cb4d3eSLandon J. Fuller obj_assert_class(macro_type, MacroType) 300777cb4d3eSLandon J. Fuller 300877cb4d3eSLandon J. Fuller return (macro_new(var_get_macro_name(var, macro_type), value)) 300977cb4d3eSLandon J. Fuller} 301077cb4d3eSLandon J. Fuller 301177cb4d3eSLandon J. Fuller# Return the preprocessor constant name to be used with `var` for the given 301277cb4d3eSLandon J. Fuller# macro_type 301377cb4d3eSLandon J. Fullerfunction var_get_macro_name(var, macro_type, _var_name, _suffix) { 301477cb4d3eSLandon J. Fuller obj_assert_class(var, Var) 301577cb4d3eSLandon J. Fuller obj_assert_class(macro_type, MacroType) 301677cb4d3eSLandon J. Fuller 301777cb4d3eSLandon J. Fuller _var_name = get(var, p_name) 301877cb4d3eSLandon J. Fuller _suffix = get(macro_type, p_const_suffix) 301977cb4d3eSLandon J. Fuller 302077cb4d3eSLandon J. Fuller return("BHND_NVAR_" toupper(_var_name) _suffix) 302177cb4d3eSLandon J. Fuller} 302277cb4d3eSLandon J. Fuller 302377cb4d3eSLandon J. Fuller# Create a new SromLayout instance 302477cb4d3eSLandon J. Fullerfunction srom_layout_new(rev_desc, _obj) 302577cb4d3eSLandon J. Fuller{ 302677cb4d3eSLandon J. Fuller _obj = obj_new(SromLayout) 302777cb4d3eSLandon J. Fuller set(_obj, p_revisions, rev_desc) 302877cb4d3eSLandon J. Fuller set(_obj, p_entries, array_new()) 302977cb4d3eSLandon J. Fuller set(_obj, p_revmap, map_new()) 303077cb4d3eSLandon J. Fuller set(_obj, p_output_var_counts, map_new()) 303177cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 303277cb4d3eSLandon J. Fuller 303377cb4d3eSLandon J. Fuller return (_obj) 303477cb4d3eSLandon J. Fuller} 303577cb4d3eSLandon J. Fuller 303677cb4d3eSLandon J. Fuller# Register a new entry with the srom layout 303777cb4d3eSLandon J. Fullerfunction srom_layout_add_entry(layout, entry, _revmap, _name, _rev_start, 303877cb4d3eSLandon J. Fuller _rev_end, _var, _prev_entry, _count, _i) 303977cb4d3eSLandon J. Fuller{ 304077cb4d3eSLandon J. Fuller obj_assert_class(layout, SromLayout) 304177cb4d3eSLandon J. Fuller obj_assert_class(entry, SromEntry) 304277cb4d3eSLandon J. Fuller 304377cb4d3eSLandon J. Fuller _layout_revmap = get(layout, p_revmap) 304477cb4d3eSLandon J. Fuller _layout_var_count = get(layout, p_output_var_counts) 304577cb4d3eSLandon J. Fuller 304677cb4d3eSLandon J. Fuller _var = get(entry, p_var) 304777cb4d3eSLandon J. Fuller _name = get(_var, p_name) 304877cb4d3eSLandon J. Fuller 304977cb4d3eSLandon J. Fuller # Add to revision array 305077cb4d3eSLandon J. Fuller array_append(get(layout, p_entries), entry) 305177cb4d3eSLandon J. Fuller 305277cb4d3eSLandon J. Fuller # Add to the revision map tables 305377cb4d3eSLandon J. Fuller _rev_start = get(get(entry, p_revisions), p_start) 305477cb4d3eSLandon J. Fuller _rev_end = get(get(entry, p_revisions), p_end) 305577cb4d3eSLandon J. Fuller 305677cb4d3eSLandon J. Fuller for (_i = _rev_start; _i <= _rev_end; _i++) { 305777cb4d3eSLandon J. Fuller # Check for existing entry 305877cb4d3eSLandon J. Fuller _prev_entry = srom_layout_find_entry(layout, _name, _i) 305977cb4d3eSLandon J. Fuller if (_prev_entry != null) { 306077cb4d3eSLandon J. Fuller error("redefinition of variable '" _name "' for SROM " \ 306177cb4d3eSLandon J. Fuller "revision " _i " (previously defined on line " \ 306277cb4d3eSLandon J. Fuller get(_prev_entry, p_line) ")") 306377cb4d3eSLandon J. Fuller } 306477cb4d3eSLandon J. Fuller 306577cb4d3eSLandon J. Fuller # Add to the (varname,revision) map 306677cb4d3eSLandon J. Fuller map_set(_layout_revmap, (_name SUBSEP _i), entry) 306777cb4d3eSLandon J. Fuller 306877cb4d3eSLandon J. Fuller # If an output variable, set or increment the output variable 306977cb4d3eSLandon J. Fuller # count 307077cb4d3eSLandon J. Fuller if (!srom_entry_should_output(entry, _i)) 307177cb4d3eSLandon J. Fuller continue 307277cb4d3eSLandon J. Fuller 307377cb4d3eSLandon J. Fuller if (!map_contains(_layout_var_count, _i)) { 307477cb4d3eSLandon J. Fuller map_set(_layout_var_count, _i, 1) 307577cb4d3eSLandon J. Fuller } else { 307677cb4d3eSLandon J. Fuller _count = map_get(_layout_var_count, _i) 307777cb4d3eSLandon J. Fuller map_set(_layout_var_count, _i, _count + 1) 307877cb4d3eSLandon J. Fuller } 307977cb4d3eSLandon J. Fuller } 308077cb4d3eSLandon J. Fuller} 308177cb4d3eSLandon J. Fuller 308277cb4d3eSLandon J. Fuller 308377cb4d3eSLandon J. Fuller# Return the variable name to be used when emitting C declarations 308477cb4d3eSLandon J. Fuller# for this SROM layout 308577cb4d3eSLandon J. Fuller# 308677cb4d3eSLandon J. Fuller# The name is gauranteed to be unique across SROM layouts with non-overlapping 308777cb4d3eSLandon J. Fuller# revision ranges 308877cb4d3eSLandon J. Fullerfunction srom_layout_get_variable_name(layout, _revs) { 308977cb4d3eSLandon J. Fuller obj_assert_class(layout, SromLayout) 309077cb4d3eSLandon J. Fuller 309177cb4d3eSLandon J. Fuller _revs = get(layout, p_revisions) 309277cb4d3eSLandon J. Fuller 309377cb4d3eSLandon J. Fuller return ("bhnd_sprom_layout_r" get(_revs, p_start) \ 309477cb4d3eSLandon J. Fuller "_r" get(_revs, p_end)) 309577cb4d3eSLandon J. Fuller} 309677cb4d3eSLandon J. Fuller 309777cb4d3eSLandon J. Fuller# Return true if the given SROM revision is defined by the layout, false 309877cb4d3eSLandon J. Fuller# otherwise 309977cb4d3eSLandon J. Fullerfunction srom_layout_has_rev(layout, rev) { 310077cb4d3eSLandon J. Fuller obj_assert_class(layout, SromLayout) 310177cb4d3eSLandon J. Fuller return (revrange_contains(get(layout, p_revisions), rev)) 310277cb4d3eSLandon J. Fuller} 310377cb4d3eSLandon J. Fuller 310477cb4d3eSLandon J. Fuller 310577cb4d3eSLandon J. Fuller# Return the total number of output variables (variables to be included 310677cb4d3eSLandon J. Fuller# in the SROM layout bindings) for the given SROM revision 310777cb4d3eSLandon J. Fullerfunction srom_layout_num_output_vars(layout, rev, _counts) 310877cb4d3eSLandon J. Fuller{ 310977cb4d3eSLandon J. Fuller obj_assert_class(layout, SromLayout) 311077cb4d3eSLandon J. Fuller 311177cb4d3eSLandon J. Fuller _counts = get(layout, p_output_var_counts) 311277cb4d3eSLandon J. Fuller if (!map_contains(_counts, rev)) 311377cb4d3eSLandon J. Fuller return (0) 311477cb4d3eSLandon J. Fuller 311577cb4d3eSLandon J. Fuller return (map_get(_counts, rev)) 311677cb4d3eSLandon J. Fuller} 311777cb4d3eSLandon J. Fuller 311877cb4d3eSLandon J. Fuller# Return the SromEntry defined for the given variable name and SROM revision, 311977cb4d3eSLandon J. Fuller# or null if none 312077cb4d3eSLandon J. Fullerfunction srom_layout_find_entry(layout, vname, revision, _key, _srom_revmap) { 312177cb4d3eSLandon J. Fuller obj_assert_class(layout, SromLayout) 312277cb4d3eSLandon J. Fuller 312377cb4d3eSLandon J. Fuller _srom_revmap = get(layout, p_revmap) 312477cb4d3eSLandon J. Fuller 312577cb4d3eSLandon J. Fuller # SromEntry are mapped by name,revision composite keys 312677cb4d3eSLandon J. Fuller _key = vname SUBSEP revision 312777cb4d3eSLandon J. Fuller if (!map_contains(_srom_revmap, _key)) 312877cb4d3eSLandon J. Fuller return (null) 312977cb4d3eSLandon J. Fuller 313077cb4d3eSLandon J. Fuller return (map_get(_srom_revmap, _key)) 313177cb4d3eSLandon J. Fuller 313277cb4d3eSLandon J. Fuller} 313377cb4d3eSLandon J. Fuller 313477cb4d3eSLandon J. Fuller# Create a new SromLayoutFilter instance, checking that `revs` 313577cb4d3eSLandon J. Fuller# falls within the parent's revision range 313677cb4d3eSLandon J. Fullerfunction srom_layout_filter_new(parent, revs, _obj, _start, _end, _parent_revs) { 313777cb4d3eSLandon J. Fuller obj_assert_class(parent, SromLayout) 313877cb4d3eSLandon J. Fuller obj_assert_class(revs, RevRange) 313977cb4d3eSLandon J. Fuller 314077cb4d3eSLandon J. Fuller # Fetch our parent's revision range, confirm that we're 314177cb4d3eSLandon J. Fuller # a strict subset 314277cb4d3eSLandon J. Fuller _start = get(revs, p_start) 314377cb4d3eSLandon J. Fuller _end = get(revs, p_end) 314477cb4d3eSLandon J. Fuller _parent_revs = get(parent, p_revisions) 314577cb4d3eSLandon J. Fuller 314677cb4d3eSLandon J. Fuller if (!revrange_contains(_parent_revs, _start)) 314777cb4d3eSLandon J. Fuller error("'" _start "' is outside of parent range") 314877cb4d3eSLandon J. Fuller 314977cb4d3eSLandon J. Fuller if (!revrange_contains(_parent_revs, _end)) 315077cb4d3eSLandon J. Fuller error("'" _end "' is outside of parent range") 315177cb4d3eSLandon J. Fuller 315277cb4d3eSLandon J. Fuller if (revrange_equal(revs, _parent_revs)) { 315377cb4d3eSLandon J. Fuller error("srom range '" revrange_to_string(revs) "' is " \ 315477cb4d3eSLandon J. Fuller "identical to parent range of '" \ 315577cb4d3eSLandon J. Fuller revrange_to_string(_parent_revs) "'") 315677cb4d3eSLandon J. Fuller } 315777cb4d3eSLandon J. Fuller 315877cb4d3eSLandon J. Fuller # Construct and return new filter instance 315977cb4d3eSLandon J. Fuller _obj = obj_new(SromLayoutFilter) 316077cb4d3eSLandon J. Fuller set(_obj, p_parent, parent) 316177cb4d3eSLandon J. Fuller set(_obj, p_revisions, revs) 316277cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 316377cb4d3eSLandon J. Fuller 316477cb4d3eSLandon J. Fuller return (_obj) 316577cb4d3eSLandon J. Fuller} 316677cb4d3eSLandon J. Fuller 316777cb4d3eSLandon J. Fuller# 316877cb4d3eSLandon J. Fuller# Create a new SromEntry instance 316977cb4d3eSLandon J. Fuller# 317077cb4d3eSLandon J. Fuller# var: The variable referenced by this entry 317177cb4d3eSLandon J. Fuller# revisions: The SROM revisions to which this entry applies 317277cb4d3eSLandon J. Fuller# base_offset: The SROM entry offset; any relative segment offsets will be 317377cb4d3eSLandon J. Fuller# calculated relative to the base offset 317477cb4d3eSLandon J. Fuller# type: The SROM's value type; this may be a subtype of the variable 317577cb4d3eSLandon J. Fuller# type, and defines the data (width, sign, etc) to be read from 317677cb4d3eSLandon J. Fuller# SROM. 317777cb4d3eSLandon J. Fuller# 317877cb4d3eSLandon J. Fullerfunction srom_entry_new(var, revisions, base_offset, type, _obj) { 317977cb4d3eSLandon J. Fuller obj_assert_class(var, Var) 318077cb4d3eSLandon J. Fuller if (revisions != null) 318177cb4d3eSLandon J. Fuller obj_assert_class(revisions, RevRange) 318277cb4d3eSLandon J. Fuller 318377cb4d3eSLandon J. Fuller _obj = obj_new(SromEntry) 318477cb4d3eSLandon J. Fuller set(_obj, p_var, var) 318577cb4d3eSLandon J. Fuller set(_obj, p_revisions, revisions) 318677cb4d3eSLandon J. Fuller set(_obj, p_base_offset, base_offset) 318777cb4d3eSLandon J. Fuller set(_obj, p_type, type) 318877cb4d3eSLandon J. Fuller set(_obj, p_offsets, array_new()) 318977cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 319077cb4d3eSLandon J. Fuller 319177cb4d3eSLandon J. Fuller return (_obj) 319277cb4d3eSLandon J. Fuller} 319377cb4d3eSLandon J. Fuller 319477cb4d3eSLandon J. Fuller# Return true if the SromEntry has an array type 319577cb4d3eSLandon J. Fullerfunction srom_entry_has_array_type(entry) { 319677cb4d3eSLandon J. Fuller obj_assert_class(entry, SromEntry) 319777cb4d3eSLandon J. Fuller 319877cb4d3eSLandon J. Fuller return (obj_is_instanceof(get(entry, p_type), ArrayType)) 319977cb4d3eSLandon J. Fuller} 320077cb4d3eSLandon J. Fuller 320177cb4d3eSLandon J. Fuller# Return the number of array elements defined by this SromEntry's type, 320277cb4d3eSLandon J. Fuller# or 1 if the entry does not have an array type. 320377cb4d3eSLandon J. Fullerfunction srom_entry_get_array_len(entry, _type) { 320477cb4d3eSLandon J. Fuller obj_assert_class(entry, SromEntry) 320577cb4d3eSLandon J. Fuller 320677cb4d3eSLandon J. Fuller return (type_get_nelem(get(entry, p_type))) 320777cb4d3eSLandon J. Fuller} 320877cb4d3eSLandon J. Fuller 320977cb4d3eSLandon J. Fuller# 321077cb4d3eSLandon J. Fuller# Return true if the given entry should be included in the output bindings 321177cb4d3eSLandon J. Fuller# generated for the given revision, false otherwise. 321277cb4d3eSLandon J. Fuller# 321377cb4d3eSLandon J. Fullerfunction srom_entry_should_output(entry, rev, _var, _revs) 321477cb4d3eSLandon J. Fuller{ 321577cb4d3eSLandon J. Fuller obj_assert_class(entry, SromEntry) 321677cb4d3eSLandon J. Fuller 321777cb4d3eSLandon J. Fuller _var = get(entry, p_var) 321877cb4d3eSLandon J. Fuller _revs = get(entry, p_revisions) 321977cb4d3eSLandon J. Fuller 322077cb4d3eSLandon J. Fuller # Exclude internal variables 322177cb4d3eSLandon J. Fuller if (var_is_internal(_var)) 322277cb4d3eSLandon J. Fuller return (0) 322377cb4d3eSLandon J. Fuller 322477cb4d3eSLandon J. Fuller # Exclude inapplicable entry revisions 322577cb4d3eSLandon J. Fuller if (!revrange_contains(_revs, rev)) 322677cb4d3eSLandon J. Fuller return (0) 322777cb4d3eSLandon J. Fuller 322877cb4d3eSLandon J. Fuller return (1) 322977cb4d3eSLandon J. Fuller} 323077cb4d3eSLandon J. Fuller 323177cb4d3eSLandon J. Fuller# 323277cb4d3eSLandon J. Fuller# Return the single, non-shifted, non-masked offset/segment for the given 323377cb4d3eSLandon J. Fuller# SromEntry, or throw an error if the entry contains multiple offsets/segments. 323477cb4d3eSLandon J. Fuller# 323577cb4d3eSLandon J. Fuller# This is used to fetch special-cased variable definitions that are required 323677cb4d3eSLandon J. Fuller# to present a single simple offset. 323777cb4d3eSLandon J. Fuller# 323877cb4d3eSLandon J. Fullerfunction srom_entry_get_single_segment(entry, _offsets, _segments, _seg, 323977cb4d3eSLandon J. Fuller _base_type, _default_mask) 324077cb4d3eSLandon J. Fuller{ 324177cb4d3eSLandon J. Fuller obj_assert_class(entry, SromEntry) 324277cb4d3eSLandon J. Fuller 324377cb4d3eSLandon J. Fuller # Fetch the single offset's segment list 324477cb4d3eSLandon J. Fuller _offsets = get(entry, p_offsets) 324577cb4d3eSLandon J. Fuller if (array_size(_offsets) != 1) 324677cb4d3eSLandon J. Fuller errorc(get(entry, p_line), "unsupported offset count") 324777cb4d3eSLandon J. Fuller 324877cb4d3eSLandon J. Fuller _segments = get(array_first(_offsets), p_segments) 324977cb4d3eSLandon J. Fuller if (array_size(_segments) != 1) 325077cb4d3eSLandon J. Fuller errorc(get(entry, p_line), "unsupported segment count") 325177cb4d3eSLandon J. Fuller 325277cb4d3eSLandon J. Fuller # Fetch the single segment 325377cb4d3eSLandon J. Fuller _seg = array_first(_segments) 325477cb4d3eSLandon J. Fuller _base_type = srom_segment_get_base_type(_seg) 325577cb4d3eSLandon J. Fuller _default_mask = get(_base_type, p_mask) 325677cb4d3eSLandon J. Fuller 325777cb4d3eSLandon J. Fuller # Must not be shifted/masked 325877cb4d3eSLandon J. Fuller if (get(_seg, p_shift) != 0) 325977cb4d3eSLandon J. Fuller errorc(obj_get_prop_nr(_seg, p_mask), "shift unsupported") 326077cb4d3eSLandon J. Fuller 326177cb4d3eSLandon J. Fuller if (get(_seg, p_mask) != _default_mask) 326277cb4d3eSLandon J. Fuller errorc(obj_get_prop_nr(_seg, p_mask), "mask unsupported") 326377cb4d3eSLandon J. Fuller 326477cb4d3eSLandon J. Fuller return (_seg) 326577cb4d3eSLandon J. Fuller} 326677cb4d3eSLandon J. Fuller 326777cb4d3eSLandon J. Fuller# Create a new SromOffset instance 326877cb4d3eSLandon J. Fullerfunction srom_offset_new(_obj) { 326977cb4d3eSLandon J. Fuller _obj = obj_new(SromOffset) 327077cb4d3eSLandon J. Fuller set(_obj, p_segments, array_new()) 327177cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 327277cb4d3eSLandon J. Fuller 327377cb4d3eSLandon J. Fuller return (_obj) 327477cb4d3eSLandon J. Fuller} 327577cb4d3eSLandon J. Fuller 327677cb4d3eSLandon J. Fuller# Return the number of SromSegment instances defined by this offset. 327777cb4d3eSLandon J. Fullerfunction srom_offset_segment_count(offset) { 327877cb4d3eSLandon J. Fuller obj_assert_class(offset, SromOffset) 327977cb4d3eSLandon J. Fuller return (array_size(get(offset, p_segments))) 328077cb4d3eSLandon J. Fuller} 328177cb4d3eSLandon J. Fuller 328277cb4d3eSLandon J. Fuller# Return the idx'th segment. Will throw an error if idx falls outside 328377cb4d3eSLandon J. Fuller# the number of available segments. 328477cb4d3eSLandon J. Fullerfunction srom_offset_get_segment(offset, idx, _segments, _seg) { 328577cb4d3eSLandon J. Fuller obj_assert_class(offset, SromOffset) 328677cb4d3eSLandon J. Fuller 328777cb4d3eSLandon J. Fuller return (array_get(get(offset, p_segments), idx)) 328877cb4d3eSLandon J. Fuller} 328977cb4d3eSLandon J. Fuller 329077cb4d3eSLandon J. Fuller# Create a new SromSegment instance 329177cb4d3eSLandon J. Fullerfunction srom_segment_new(offset, type, mask, shift, value, _obj) { 329277cb4d3eSLandon J. Fuller _obj = obj_new(SromSegment) 329377cb4d3eSLandon J. Fuller set(_obj, p_offset, offset) 329477cb4d3eSLandon J. Fuller set(_obj, p_type, type) 329577cb4d3eSLandon J. Fuller set(_obj, p_mask, mask) 329677cb4d3eSLandon J. Fuller set(_obj, p_shift, shift) 329777cb4d3eSLandon J. Fuller set(_obj, p_value, value) 329877cb4d3eSLandon J. Fuller set(_obj, p_line, NR) 329977cb4d3eSLandon J. Fuller 330077cb4d3eSLandon J. Fuller return (_obj) 330177cb4d3eSLandon J. Fuller} 330277cb4d3eSLandon J. Fuller 330377cb4d3eSLandon J. Fuller# Return true if the segment has an array type 330477cb4d3eSLandon J. Fullerfunction srom_segment_has_array_type(seg, _type) { 330577cb4d3eSLandon J. Fuller _type = srom_segment_get_type(seg) 330677cb4d3eSLandon J. Fuller return (obj_is_instanceof(_type, ArrayType)) 330777cb4d3eSLandon J. Fuller} 330877cb4d3eSLandon J. Fuller 330977cb4d3eSLandon J. Fuller# Return the array count of the segment, or 1 if the segment does not have 331077cb4d3eSLandon J. Fuller# an array type 331177cb4d3eSLandon J. Fullerfunction srom_segment_get_array_len(seg, _type) { 331277cb4d3eSLandon J. Fuller if (!srom_segment_has_array_type(seg)) 331377cb4d3eSLandon J. Fuller return (1) 331477cb4d3eSLandon J. Fuller 331577cb4d3eSLandon J. Fuller _type = srom_segment_get_type(seg) 331677cb4d3eSLandon J. Fuller return (get(_type, p_count)) 331777cb4d3eSLandon J. Fuller} 331877cb4d3eSLandon J. Fuller 331977cb4d3eSLandon J. Fuller# Return the type of the segment 332077cb4d3eSLandon J. Fullerfunction srom_segment_get_type(seg) { 332177cb4d3eSLandon J. Fuller obj_assert_class(seg, SromSegment) 332277cb4d3eSLandon J. Fuller return (get(seg, p_type)) 332377cb4d3eSLandon J. Fuller 332477cb4d3eSLandon J. Fuller} 332577cb4d3eSLandon J. Fuller 332677cb4d3eSLandon J. Fuller# Return the base type of the segment 332777cb4d3eSLandon J. Fullerfunction srom_segment_get_base_type(seg) { 332877cb4d3eSLandon J. Fuller return (type_get_base(srom_segment_get_type(seg))) 332977cb4d3eSLandon J. Fuller} 333077cb4d3eSLandon J. Fuller 333177cb4d3eSLandon J. Fuller# Return true if the two segments have identical types and attributes (i.e. 333277cb4d3eSLandon J. Fuller# differing only by offset) 333377cb4d3eSLandon J. Fullerfunction srom_segment_attributes_equal(lhs, rhs) { 333477cb4d3eSLandon J. Fuller obj_assert_class(lhs, SromSegment) 333577cb4d3eSLandon J. Fuller obj_assert_class(rhs, SromSegment) 333677cb4d3eSLandon J. Fuller 333777cb4d3eSLandon J. Fuller # type 333877cb4d3eSLandon J. Fuller if (!type_equal(get(lhs, p_type), get(rhs, p_type))) 333977cb4d3eSLandon J. Fuller return (0) 334077cb4d3eSLandon J. Fuller 334177cb4d3eSLandon J. Fuller # mask 334277cb4d3eSLandon J. Fuller if (get(lhs, p_mask) != get(rhs, p_mask)) 334377cb4d3eSLandon J. Fuller return (0) 334477cb4d3eSLandon J. Fuller 334577cb4d3eSLandon J. Fuller # shift 334677cb4d3eSLandon J. Fuller if (get(lhs, p_shift) != get(rhs, p_shift)) 334777cb4d3eSLandon J. Fuller return (0) 334877cb4d3eSLandon J. Fuller 334977cb4d3eSLandon J. Fuller # value 335077cb4d3eSLandon J. Fuller if (get(lhs, p_value) != get(rhs, p_value)) 335177cb4d3eSLandon J. Fuller return (0) 335277cb4d3eSLandon J. Fuller 335377cb4d3eSLandon J. Fuller return (1) 335477cb4d3eSLandon J. Fuller} 335577cb4d3eSLandon J. Fuller 335677cb4d3eSLandon J. Fuller# Return a human-readable representation of a Segment instance 335777cb4d3eSLandon J. Fullerfunction segment_to_string(seg, _str, _t, _m, _s, _attrs, _attr_str) { 335877cb4d3eSLandon J. Fuller _attrs = array_new() 335977cb4d3eSLandon J. Fuller 336077cb4d3eSLandon J. Fuller # include type (if specified) 336177cb4d3eSLandon J. Fuller if ((_t = get(seg, p_type)) != null) 336277cb4d3eSLandon J. Fuller _str = (type_to_string(_t) " ") 336377cb4d3eSLandon J. Fuller 336477cb4d3eSLandon J. Fuller # include offset 336577cb4d3eSLandon J. Fuller _str = (_str sprintf("0x%X", get(seg, p_offset))) 336677cb4d3eSLandon J. Fuller 336777cb4d3eSLandon J. Fuller # append list of attributes 336877cb4d3eSLandon J. Fuller if ((_m = get(seg, p_mask)) != null) 336977cb4d3eSLandon J. Fuller array_append(_attrs, ("&" _m)) 337077cb4d3eSLandon J. Fuller 337177cb4d3eSLandon J. Fuller if ((_s = get(seg, p_shift)) != null) { 337277cb4d3eSLandon J. Fuller if (_s > 0) 337377cb4d3eSLandon J. Fuller _s = ">>" _s 337477cb4d3eSLandon J. Fuller else 337577cb4d3eSLandon J. Fuller _s = "<<" _s 337677cb4d3eSLandon J. Fuller array_append(_attrs, _s) 337777cb4d3eSLandon J. Fuller } 337877cb4d3eSLandon J. Fuller 337977cb4d3eSLandon J. Fuller _attr_str = array_join(_attrs, ", ") 338077cb4d3eSLandon J. Fuller obj_delete(_attrs) 338177cb4d3eSLandon J. Fuller 338277cb4d3eSLandon J. Fuller if (_attr_str == "") 338377cb4d3eSLandon J. Fuller return (_str) 338477cb4d3eSLandon J. Fuller else 338577cb4d3eSLandon J. Fuller return (_str " (" _attr_str ")") 338677cb4d3eSLandon J. Fuller} 338777cb4d3eSLandon J. Fuller 338877cb4d3eSLandon J. Fuller# return the flag definition for variable `v` 338977cb4d3eSLandon J. Fullerfunction gen_var_flags(v, _type, _flags, _flag, _str) 339077cb4d3eSLandon J. Fuller{ 339177cb4d3eSLandon J. Fuller _num_flags = 0; 339277cb4d3eSLandon J. Fuller _type = get(v, p_type) 339377cb4d3eSLandon J. Fuller _flags = array_new() 339477cb4d3eSLandon J. Fuller 339577cb4d3eSLandon J. Fuller # VF_PRIVATE 339677cb4d3eSLandon J. Fuller if (get(v, p_access) == VAccessPrivate) 339777cb4d3eSLandon J. Fuller array_append(_flags, VFlagPrivate) 339877cb4d3eSLandon J. Fuller 339977cb4d3eSLandon J. Fuller # VF_IGNALL1 340077cb4d3eSLandon J. Fuller if (get(v, p_ignall1)) 340177cb4d3eSLandon J. Fuller array_append(_flags, VFlagIgnoreAll1) 340277cb4d3eSLandon J. Fuller 340377cb4d3eSLandon J. Fuller # If empty, return empty flag value 340477cb4d3eSLandon J. Fuller if (array_size(_flags) == 0) { 340577cb4d3eSLandon J. Fuller obj_delete(_flags) 340677cb4d3eSLandon J. Fuller return ("0") 340777cb4d3eSLandon J. Fuller } 340877cb4d3eSLandon J. Fuller 340977cb4d3eSLandon J. Fuller # Join all flag constants with | 341077cb4d3eSLandon J. Fuller _str = array_join(_flags, "|", class_get_prop_id(VFlag, p_const)) 341177cb4d3eSLandon J. Fuller 341277cb4d3eSLandon J. Fuller # Clean up 341377cb4d3eSLandon J. Fuller obj_delete(_flags) 341477cb4d3eSLandon J. Fuller 341577cb4d3eSLandon J. Fuller return (_str) 341677cb4d3eSLandon J. Fuller} 341777cb4d3eSLandon J. Fuller 341877cb4d3eSLandon J. Fuller# 341977cb4d3eSLandon J. Fuller# Return the absolute value 342077cb4d3eSLandon J. Fuller# 342177cb4d3eSLandon J. Fullerfunction abs(i) { 342277cb4d3eSLandon J. Fuller return (i < 0 ? -i : i) 342377cb4d3eSLandon J. Fuller} 342477cb4d3eSLandon J. Fuller 342577cb4d3eSLandon J. Fuller# 342677cb4d3eSLandon J. Fuller# Return the minimum of two values 342777cb4d3eSLandon J. Fuller# 342877cb4d3eSLandon J. Fullerfunction min(lhs, rhs) { 342977cb4d3eSLandon J. Fuller return (lhs < rhs ? lhs : rhs) 343077cb4d3eSLandon J. Fuller} 343177cb4d3eSLandon J. Fuller 343277cb4d3eSLandon J. Fuller# 343377cb4d3eSLandon J. Fuller# Return the maximum of two values 343477cb4d3eSLandon J. Fuller# 343577cb4d3eSLandon J. Fullerfunction max(lhs, rhs) { 343677cb4d3eSLandon J. Fuller return (lhs > rhs ? lhs : rhs) 343777cb4d3eSLandon J. Fuller} 343877cb4d3eSLandon J. Fuller 343977cb4d3eSLandon J. Fuller# 344077cb4d3eSLandon J. Fuller# Parse a hex string 344177cb4d3eSLandon J. Fuller# 344277cb4d3eSLandon J. Fullerfunction parse_hex_string(str, _hex_pstate, _out, _p, _count) { 344377cb4d3eSLandon J. Fuller if (!AWK_REQ_HEX_PARSING) 344477cb4d3eSLandon J. Fuller return (str + 0) 344577cb4d3eSLandon J. Fuller 344677cb4d3eSLandon J. Fuller # Populate hex parsing lookup table on-demand 344777cb4d3eSLandon J. Fuller if (!("F" in _g_hex_table)) { 344877cb4d3eSLandon J. Fuller for (_p = 0; _p < 16; _p++) { 344977cb4d3eSLandon J. Fuller _g_hex_table[sprintf("%X", _p)] = _p 345077cb4d3eSLandon J. Fuller _g_hex_table[sprintf("%x", _p)] = _p 345177cb4d3eSLandon J. Fuller } 345277cb4d3eSLandon J. Fuller } 345377cb4d3eSLandon J. Fuller 345477cb4d3eSLandon J. Fuller # Split input into an array 345577cb4d3eSLandon J. Fuller _count = split(toupper(str), _hex_pstate, "") 345677cb4d3eSLandon J. Fuller _p = 1 345777cb4d3eSLandon J. Fuller 345877cb4d3eSLandon J. Fuller # Skip leading '0x' 345977cb4d3eSLandon J. Fuller if (_count >= 2 && _hex_pstate[1] == "0") { 346077cb4d3eSLandon J. Fuller if (_hex_pstate[2] == "x" || _hex_pstate[2] == "X") 346177cb4d3eSLandon J. Fuller _p += 2 346277cb4d3eSLandon J. Fuller } 346377cb4d3eSLandon J. Fuller 346477cb4d3eSLandon J. Fuller # Parse the hex_digits 346577cb4d3eSLandon J. Fuller _out = 0 346677cb4d3eSLandon J. Fuller for (; _p <= _count; _p++) 346777cb4d3eSLandon J. Fuller _out = (_out * 16) + _g_hex_table[_hex_pstate[_p]] 346877cb4d3eSLandon J. Fuller 346977cb4d3eSLandon J. Fuller return (_out) 347077cb4d3eSLandon J. Fuller} 347177cb4d3eSLandon J. Fuller 347277cb4d3eSLandon J. Fuller# 347377cb4d3eSLandon J. Fuller# Return the integer representation of an unsigned decimal, hexadecimal, or 347477cb4d3eSLandon J. Fuller# octal string 347577cb4d3eSLandon J. Fuller# 347677cb4d3eSLandon J. Fullerfunction parse_uint_string(str) { 347777cb4d3eSLandon J. Fuller if (str ~ UINT_REGEX) 347877cb4d3eSLandon J. Fuller return (int(str)) 347977cb4d3eSLandon J. Fuller else if (str ~ HEX_REGEX) 348077cb4d3eSLandon J. Fuller return (parse_hex_string(str)) 348177cb4d3eSLandon J. Fuller else 348277cb4d3eSLandon J. Fuller error("invalid integer value: '" str "'") 348377cb4d3eSLandon J. Fuller} 348477cb4d3eSLandon J. Fuller 348577cb4d3eSLandon J. Fuller# 348677cb4d3eSLandon J. Fuller# Parse an offset string, stripping any leading '+' or trailing ':' or ',' 348777cb4d3eSLandon J. Fuller# characters 348877cb4d3eSLandon J. Fuller# 348977cb4d3eSLandon J. Fuller# +0x0: 349077cb4d3eSLandon J. Fuller# 0x0, 349177cb4d3eSLandon J. Fuller# ... 349277cb4d3eSLandon J. Fuller# 349377cb4d3eSLandon J. Fullerfunction parse_uint_offset(str) { 349477cb4d3eSLandon J. Fuller # Drop any leading '+' 349577cb4d3eSLandon J. Fuller sub(/^\+/, "", str) 349677cb4d3eSLandon J. Fuller 349777cb4d3eSLandon J. Fuller # Drop any trailing ':', ',', or '|' 349877cb4d3eSLandon J. Fuller sub("[,|:]$", "", str) 349977cb4d3eSLandon J. Fuller 350077cb4d3eSLandon J. Fuller # Parse the cleaned up string 350177cb4d3eSLandon J. Fuller return (parse_uint_string(str)) 3502e83ce340SAdrian Chadd} 3503e83ce340SAdrian Chadd 3504e83ce340SAdrian Chadd# 3505e83ce340SAdrian Chadd# Print msg to output file, without indentation 3506e83ce340SAdrian Chadd# 350777cb4d3eSLandon J. Fullerfunction emit_ni(msg) { 3508e83ce340SAdrian Chadd printf("%s", msg) >> OUTPUT_FILE 3509e83ce340SAdrian Chadd} 3510e83ce340SAdrian Chadd 3511e83ce340SAdrian Chadd# 3512e83ce340SAdrian Chadd# Print msg to output file, indented for the current `output_depth` 3513e83ce340SAdrian Chadd# 351477cb4d3eSLandon J. Fullerfunction emit(msg, _ind) { 3515e83ce340SAdrian Chadd for (_ind = 0; _ind < output_depth; _ind++) 3516e83ce340SAdrian Chadd emit_ni("\t") 3517e83ce340SAdrian Chadd 3518e83ce340SAdrian Chadd emit_ni(msg) 3519e83ce340SAdrian Chadd} 3520e83ce340SAdrian Chadd 3521e83ce340SAdrian Chadd# 3522e83ce340SAdrian Chadd# Print a warning to stderr 3523e83ce340SAdrian Chadd# 352477cb4d3eSLandon J. Fullerfunction warn(msg) { 3525e83ce340SAdrian Chadd print "warning:", msg, "at", FILENAME, "line", NR > "/dev/stderr" 3526e83ce340SAdrian Chadd} 3527e83ce340SAdrian Chadd 3528e83ce340SAdrian Chadd# 352977cb4d3eSLandon J. Fuller# Print an warning message without including the source line information 353077cb4d3eSLandon J. Fuller# 353177cb4d3eSLandon J. Fullerfunction warnx(msg) { 353277cb4d3eSLandon J. Fuller print "warning:", msg > "/dev/stderr" 353377cb4d3eSLandon J. Fuller} 353477cb4d3eSLandon J. Fuller 353577cb4d3eSLandon J. Fuller# 353677cb4d3eSLandon J. Fuller# Print a compiler error to stderr with a caller supplied 353777cb4d3eSLandon J. Fuller# line number 353877cb4d3eSLandon J. Fuller# 353977cb4d3eSLandon J. Fullerfunction errorc(line, msg) { 354077cb4d3eSLandon J. Fuller errorx(msg " at " FILENAME " line " line) 354177cb4d3eSLandon J. Fuller} 354277cb4d3eSLandon J. Fuller 354377cb4d3eSLandon J. Fuller# 3544e83ce340SAdrian Chadd# Print a compiler error to stderr 3545e83ce340SAdrian Chadd# 354677cb4d3eSLandon J. Fullerfunction error(msg) { 3547e83ce340SAdrian Chadd errorx(msg " at " FILENAME " line " NR ":\n\t" $0) 3548e83ce340SAdrian Chadd} 3549e83ce340SAdrian Chadd 3550e83ce340SAdrian Chadd# 3551e83ce340SAdrian Chadd# Print an error message without including the source line information 3552e83ce340SAdrian Chadd# 355377cb4d3eSLandon J. Fullerfunction errorx(msg) { 3554e83ce340SAdrian Chadd print "error:", msg > "/dev/stderr" 3555e83ce340SAdrian Chadd _EARLY_EXIT=1 3556e83ce340SAdrian Chadd exit 1 3557e83ce340SAdrian Chadd} 3558e83ce340SAdrian Chadd 3559e83ce340SAdrian Chadd# 3560e83ce340SAdrian Chadd# Print a debug output message 3561e83ce340SAdrian Chadd# 356277cb4d3eSLandon J. Fullerfunction debug(msg, _i) { 3563e83ce340SAdrian Chadd if (!DEBUG) 3564e83ce340SAdrian Chadd return 356577cb4d3eSLandon J. Fuller for (_i = 1; _i < _g_parse_stack_depth; _i++) 3566e83ce340SAdrian Chadd printf("\t") > "/dev/stderr" 3567e83ce340SAdrian Chadd print msg > "/dev/stderr" 3568e83ce340SAdrian Chadd} 3569e83ce340SAdrian Chadd 3570e83ce340SAdrian Chadd# 3571e83ce340SAdrian Chadd# Advance to the next non-comment input record 3572e83ce340SAdrian Chadd# 357377cb4d3eSLandon J. Fullerfunction next_line(_result) { 3574e83ce340SAdrian Chadd do { 3575e83ce340SAdrian Chadd _result = getline 3576e83ce340SAdrian Chadd } while (_result > 0 && $0 ~ /^[ \t]*#.*/) # skip comment lines 3577e83ce340SAdrian Chadd return (_result) 3578e83ce340SAdrian Chadd} 3579e83ce340SAdrian Chadd 3580e83ce340SAdrian Chadd# 3581e83ce340SAdrian Chadd# Advance to the next input record and verify that it matches @p regex 3582e83ce340SAdrian Chadd# 358377cb4d3eSLandon J. Fullerfunction getline_matching(regex, _result) { 3584e83ce340SAdrian Chadd _result = next_line() 3585e83ce340SAdrian Chadd if (_result <= 0) 3586e83ce340SAdrian Chadd return (_result) 3587e83ce340SAdrian Chadd 3588e83ce340SAdrian Chadd if ($0 ~ regex) 3589e83ce340SAdrian Chadd return (1) 3590e83ce340SAdrian Chadd 3591e83ce340SAdrian Chadd return (-1) 3592e83ce340SAdrian Chadd} 3593e83ce340SAdrian Chadd 3594e83ce340SAdrian Chadd# 3595e83ce340SAdrian Chadd# Shift the current fields left by `n`. 3596e83ce340SAdrian Chadd# 3597e83ce340SAdrian Chadd# If all fields are consumed and the optional do_getline argument is true, 3598e83ce340SAdrian Chadd# read the next line. 3599e83ce340SAdrian Chadd# 360077cb4d3eSLandon J. Fullerfunction shiftf(n, do_getline, _i) { 360177cb4d3eSLandon J. Fuller if (n > NF) 360277cb4d3eSLandon J. Fuller error("shift past end of line") 360377cb4d3eSLandon J. Fuller 360477cb4d3eSLandon J. Fuller if (n == NF) { 360577cb4d3eSLandon J. Fuller # If shifting the entire line, just reset the line value 360677cb4d3eSLandon J. Fuller $0 = "" 360777cb4d3eSLandon J. Fuller } else { 360877cb4d3eSLandon J. Fuller for (_i = 1; _i <= NF-n; _i++) { 360977cb4d3eSLandon J. Fuller $(_i) = $(_i+n) 3610e83ce340SAdrian Chadd } 3611e83ce340SAdrian Chadd NF = NF - n 361277cb4d3eSLandon J. Fuller } 3613e83ce340SAdrian Chadd 3614e83ce340SAdrian Chadd if (NF == 0 && do_getline) 3615e83ce340SAdrian Chadd next_line() 3616e83ce340SAdrian Chadd} 3617e83ce340SAdrian Chadd 3618e83ce340SAdrian Chadd# Push a new parser state. 361977cb4d3eSLandon J. Fullerfunction parser_state_push(ctx, is_block, _state) { 362077cb4d3eSLandon J. Fuller _state = obj_new(ParseState) 362177cb4d3eSLandon J. Fuller set(_state, p_ctx, ctx) 362277cb4d3eSLandon J. Fuller set(_state, p_is_block, is_block) 362377cb4d3eSLandon J. Fuller set(_state, p_line, NR) 362477cb4d3eSLandon J. Fuller 362577cb4d3eSLandon J. Fuller _g_parse_stack_depth++ 362677cb4d3eSLandon J. Fuller _g_parse_stack[_g_parse_stack_depth] = _state 3627e83ce340SAdrian Chadd} 3628e83ce340SAdrian Chadd 362977cb4d3eSLandon J. Fuller# Fetch the current parser state 363077cb4d3eSLandon J. Fullerfunction parser_state_get() { 363177cb4d3eSLandon J. Fuller if (_g_parse_stack_depth == 0) 363277cb4d3eSLandon J. Fuller errorx("parser_state_get() called with empty parse stack") 363377cb4d3eSLandon J. Fuller 363477cb4d3eSLandon J. Fuller return (_g_parse_stack[_g_parse_stack_depth]) 3635e83ce340SAdrian Chadd} 363677cb4d3eSLandon J. Fuller 363777cb4d3eSLandon J. Fuller# Pop the current parser state 363877cb4d3eSLandon J. Fullerfunction parser_state_pop(_block_state, _closes_block) { 363977cb4d3eSLandon J. Fuller if (_g_parse_stack_depth == 0) 364077cb4d3eSLandon J. Fuller errorx("parser_state_pop() called with empty parse stack") 364177cb4d3eSLandon J. Fuller 364277cb4d3eSLandon J. Fuller _closes_block = get(parser_state_get(), p_is_block) 364377cb4d3eSLandon J. Fuller 364477cb4d3eSLandon J. Fuller delete _g_parse_stack[_g_parse_stack_depth] 364577cb4d3eSLandon J. Fuller _g_parse_stack_depth-- 364677cb4d3eSLandon J. Fuller 364777cb4d3eSLandon J. Fuller if (_closes_block) 364877cb4d3eSLandon J. Fuller debug("}") 364977cb4d3eSLandon J. Fuller} 365077cb4d3eSLandon J. Fuller 365177cb4d3eSLandon J. Fuller# Fetch the current context object associated with this parser state 365277cb4d3eSLandon J. Fuller# The object will be asserted as being an instance of the given class. 365377cb4d3eSLandon J. Fullerfunction parser_state_get_context(class, _ctx_obj) { 365477cb4d3eSLandon J. Fuller _ctx_obj = get(parser_state_get(), p_ctx) 365577cb4d3eSLandon J. Fuller obj_assert_class(_ctx_obj, class) 365677cb4d3eSLandon J. Fuller 365777cb4d3eSLandon J. Fuller return (_ctx_obj) 365877cb4d3eSLandon J. Fuller} 365977cb4d3eSLandon J. Fuller 366077cb4d3eSLandon J. Fuller# Walk the parser state stack until a context object of the given class 366177cb4d3eSLandon J. Fuller# is found. If the top of the stack is reached without finding a context object 366277cb4d3eSLandon J. Fuller# of the requested type, an error will be thrown. 366377cb4d3eSLandon J. Fullerfunction parser_state_find_context(class, _state, _ctx, _i) { 366477cb4d3eSLandon J. Fuller if (class == null) 366577cb4d3eSLandon J. Fuller errorx("parser_state_find_context() called with null class") 366677cb4d3eSLandon J. Fuller 366777cb4d3eSLandon J. Fuller # Find the first context instance inheriting from `class` 366877cb4d3eSLandon J. Fuller for (_i = 0; _i < _g_parse_stack_depth; _i++) { 366977cb4d3eSLandon J. Fuller _state = _g_parse_stack[_g_parse_stack_depth - _i] 367077cb4d3eSLandon J. Fuller _ctx = get(_state, p_ctx) 367177cb4d3eSLandon J. Fuller 367277cb4d3eSLandon J. Fuller # Check for match 367377cb4d3eSLandon J. Fuller if (obj_is_instanceof(_ctx, class)) 367477cb4d3eSLandon J. Fuller return (_ctx) 367577cb4d3eSLandon J. Fuller } 367677cb4d3eSLandon J. Fuller 367777cb4d3eSLandon J. Fuller # Not found 367877cb4d3eSLandon J. Fuller errorx("no context instance of type '" class_get_name(class) "' " \ 367977cb4d3eSLandon J. Fuller "found in parse stack") 3680e83ce340SAdrian Chadd} 3681e83ce340SAdrian Chadd 3682e83ce340SAdrian Chadd# 3683e83ce340SAdrian Chadd# Find opening brace and push a new parser state for a brace-delimited block. 3684e83ce340SAdrian Chadd# 368577cb4d3eSLandon J. Fullerfunction parser_state_open_block(ctx) { 3686e83ce340SAdrian Chadd if ($0 ~ "{" || getline_matching("^[ \t]*{") > 0) { 368777cb4d3eSLandon J. Fuller parser_state_push(ctx, 1) 368877cb4d3eSLandon J. Fuller sub("^[^{]*{", "", $0) 3689e83ce340SAdrian Chadd return 3690e83ce340SAdrian Chadd } 3691e83ce340SAdrian Chadd 369277cb4d3eSLandon J. Fuller error("found '"$1 "' instead of expected '{'") 3693e83ce340SAdrian Chadd} 3694e83ce340SAdrian Chadd 3695e83ce340SAdrian Chadd# 3696e83ce340SAdrian Chadd# Find closing brace and pop parser states until the first 3697e83ce340SAdrian Chadd# brace-delimited block is discarded. 3698e83ce340SAdrian Chadd# 369977cb4d3eSLandon J. Fullerfunction parser_state_close_block(_next_state, _found_block) { 3700e83ce340SAdrian Chadd if ($0 !~ "}") 3701e83ce340SAdrian Chadd error("internal error - no closing brace") 3702e83ce340SAdrian Chadd 3703e83ce340SAdrian Chadd # pop states until we exit the first enclosing block 3704e83ce340SAdrian Chadd do { 370577cb4d3eSLandon J. Fuller _next_state = parser_state_get() 370677cb4d3eSLandon J. Fuller _found_block = get(_next_state, p_is_block) 370777cb4d3eSLandon J. Fuller parser_state_pop() 370877cb4d3eSLandon J. Fuller } while (!_found_block) 3709e83ce340SAdrian Chadd 3710e83ce340SAdrian Chadd # strip everything prior to the block closure 3711e83ce340SAdrian Chadd sub("^[^}]*}", "", $0) 3712e83ce340SAdrian Chadd} 3713e83ce340SAdrian Chadd 371477cb4d3eSLandon J. Fuller# Evaluates to true if the current parser state is defined with a context of 371577cb4d3eSLandon J. Fuller# the given class 371677cb4d3eSLandon J. Fullerfunction in_parser_context(class, _ctx) { 371777cb4d3eSLandon J. Fuller if (class == null) 371877cb4d3eSLandon J. Fuller errorx("called in_parser_context() with null class") 3719e83ce340SAdrian Chadd 372077cb4d3eSLandon J. Fuller _ctx = get(parser_state_get(), p_ctx) 372177cb4d3eSLandon J. Fuller return (obj_is_instanceof(_ctx, class)) 3722e83ce340SAdrian Chadd} 3723e83ce340SAdrian Chadd 3724e83ce340SAdrian Chadd# 372577cb4d3eSLandon J. Fuller# Parse and return a revision range from the current line. 3726e83ce340SAdrian Chadd# 372777cb4d3eSLandon J. Fuller# 4 372877cb4d3eSLandon J. Fuller# 4-10 # revisions 4-10, inclusive 372977cb4d3eSLandon J. Fuller# > 4 373077cb4d3eSLandon J. Fuller# < 4 373177cb4d3eSLandon J. Fuller# >= 4 373277cb4d3eSLandon J. Fuller# <= 4 3733e83ce340SAdrian Chadd# 373477cb4d3eSLandon J. Fullerfunction parse_revrange(_start, _end, _robj) { 373577cb4d3eSLandon J. Fuller _start = 0 373677cb4d3eSLandon J. Fuller _end = 0 3737e83ce340SAdrian Chadd 373877cb4d3eSLandon J. Fuller if ($2 ~ "[0-9]*-[0-9*]") { 373977cb4d3eSLandon J. Fuller split($2, _g_rev_range, "[ \t]*-[ \t]*") 374077cb4d3eSLandon J. Fuller _start = int(_g_rev_range[1]) 374177cb4d3eSLandon J. Fuller _end = int(_g_rev_range[2]) 374277cb4d3eSLandon J. Fuller } else if ($2 ~ "(>|>=|<|<=)" && $3 ~ "[1-9][0-9]*") { 374377cb4d3eSLandon J. Fuller if ($2 == ">") { 374477cb4d3eSLandon J. Fuller _start = int($3)+1 374577cb4d3eSLandon J. Fuller _end = REV_MAX 374677cb4d3eSLandon J. Fuller } else if ($2 == ">=") { 374777cb4d3eSLandon J. Fuller _start = int($3) 374877cb4d3eSLandon J. Fuller _end = REV_MAX 374977cb4d3eSLandon J. Fuller } else if ($2 == "<" && int($3) > 0) { 375077cb4d3eSLandon J. Fuller _start = 0 375177cb4d3eSLandon J. Fuller _end = int($3)-1 375277cb4d3eSLandon J. Fuller } else if ($2 == "<=") { 375377cb4d3eSLandon J. Fuller _start = 0 375477cb4d3eSLandon J. Fuller _end = int($3)-1 3755e83ce340SAdrian Chadd } else { 375677cb4d3eSLandon J. Fuller error("invalid revision descriptor") 3757e83ce340SAdrian Chadd } 375877cb4d3eSLandon J. Fuller } else if ($2 ~ "[1-9][0-9]*") { 375977cb4d3eSLandon J. Fuller _start = int($2) 376077cb4d3eSLandon J. Fuller _end = int($2) 376177cb4d3eSLandon J. Fuller } else { 376277cb4d3eSLandon J. Fuller error("invalid revision descriptor") 376377cb4d3eSLandon J. Fuller } 376477cb4d3eSLandon J. Fuller 376577cb4d3eSLandon J. Fuller return (revrange_new(_start, _end)) 3766e83ce340SAdrian Chadd} 3767e83ce340SAdrian Chadd 3768e83ce340SAdrian Chadd# 376977cb4d3eSLandon J. Fuller# Parse a variable group block starting at the current line 3770e83ce340SAdrian Chadd# 377177cb4d3eSLandon J. Fuller# group "Group Name" { 377277cb4d3eSLandon J. Fuller# u8 var_name[10] { 377377cb4d3eSLandon J. Fuller# ... 377477cb4d3eSLandon J. Fuller# } 377577cb4d3eSLandon J. Fuller# ... 377677cb4d3eSLandon J. Fuller# } 377777cb4d3eSLandon J. Fuller# 377877cb4d3eSLandon J. Fullerfunction parse_variable_group(_ctx, _groups, _group, _group_name) { 377977cb4d3eSLandon J. Fuller _ctx = parser_state_get_context(NVRAM) 378077cb4d3eSLandon J. Fuller 378177cb4d3eSLandon J. Fuller # Seek to the start of the name string 378277cb4d3eSLandon J. Fuller shiftf(1) 378377cb4d3eSLandon J. Fuller 378477cb4d3eSLandon J. Fuller # Parse the first line 378577cb4d3eSLandon J. Fuller _group_name = stringconstant_parse_line($0) 378677cb4d3eSLandon J. Fuller 378777cb4d3eSLandon J. Fuller # Incrementally parse line continuations 378877cb4d3eSLandon J. Fuller while (get(_group_name, p_continued)) { 378977cb4d3eSLandon J. Fuller getline 379077cb4d3eSLandon J. Fuller stringconstant_append_line(_group_name, $0) 379177cb4d3eSLandon J. Fuller } 379277cb4d3eSLandon J. Fuller 379377cb4d3eSLandon J. Fuller debug("group \"" get(_group_name, p_value) "\" {") 379477cb4d3eSLandon J. Fuller 379577cb4d3eSLandon J. Fuller # Register the new variable group 379677cb4d3eSLandon J. Fuller _groups = get(_ctx, p_var_groups) 379777cb4d3eSLandon J. Fuller _group = var_group_new(_group_name) 379877cb4d3eSLandon J. Fuller array_append(_groups, _group) 379977cb4d3eSLandon J. Fuller 380077cb4d3eSLandon J. Fuller # Push our variable group block 380177cb4d3eSLandon J. Fuller parser_state_open_block(_group) 380277cb4d3eSLandon J. Fuller} 380377cb4d3eSLandon J. Fuller 380477cb4d3eSLandon J. Fuller 380577cb4d3eSLandon J. Fuller# 380677cb4d3eSLandon J. Fuller# Parse a variable definition block starting at the current line 380777cb4d3eSLandon J. Fuller# 380877cb4d3eSLandon J. Fuller# u8 var_name[10] { 380977cb4d3eSLandon J. Fuller# all1 ignore 381077cb4d3eSLandon J. Fuller# desc ... 381177cb4d3eSLandon J. Fuller# } 381277cb4d3eSLandon J. Fuller# 381377cb4d3eSLandon J. Fullerfunction parse_variable_defn(_ctx, _vaccess, _type, _name, _fmt, _var, 381477cb4d3eSLandon J. Fuller _var_list) 3815e83ce340SAdrian Chadd{ 381677cb4d3eSLandon J. Fuller _ctx = parser_state_get_context(SymbolContext) 3817e83ce340SAdrian Chadd 381877cb4d3eSLandon J. Fuller # Check for access modifier 381977cb4d3eSLandon J. Fuller if ($1 == "private") { 382077cb4d3eSLandon J. Fuller _vaccess = VAccessPrivate 382177cb4d3eSLandon J. Fuller shiftf(1) 382277cb4d3eSLandon J. Fuller } else if ($1 == "internal") { 382377cb4d3eSLandon J. Fuller _vaccess = VAccessInternal 3824e83ce340SAdrian Chadd shiftf(1) 3825e83ce340SAdrian Chadd } else { 382677cb4d3eSLandon J. Fuller _vaccess = VAccessPublic 3827e83ce340SAdrian Chadd } 3828e83ce340SAdrian Chadd 382977cb4d3eSLandon J. Fuller # Find the base type 383077cb4d3eSLandon J. Fuller if ((_type = type_named($1)) == null) 383177cb4d3eSLandon J. Fuller error("unknown type '" $1 "'") 3832e83ce340SAdrian Chadd 383377cb4d3eSLandon J. Fuller # Parse (and trim) any array specifier from the variable name 383477cb4d3eSLandon J. Fuller _name = $2 383577cb4d3eSLandon J. Fuller _type = parse_array_type_specifier(_name, _type) 383677cb4d3eSLandon J. Fuller sub(ARRAY_REGEX"$", "", _name) 383777cb4d3eSLandon J. Fuller 383877cb4d3eSLandon J. Fuller # Look for an existing variable definition 383977cb4d3eSLandon J. Fuller if (_name in _g_var_names) { 384077cb4d3eSLandon J. Fuller error("variable identifier '" _name "' previously defined at " \ 384177cb4d3eSLandon J. Fuller "line " get(_g_var_names[_name], p_line)) 384277cb4d3eSLandon J. Fuller } 384377cb4d3eSLandon J. Fuller 384477cb4d3eSLandon J. Fuller # Construct new variable instance 384577cb4d3eSLandon J. Fuller _var = var_new(_vaccess, _name, _type) 384677cb4d3eSLandon J. Fuller debug((_private ? "private " : "") type_to_string(_type) " " _name " {") 384777cb4d3eSLandon J. Fuller 384877cb4d3eSLandon J. Fuller # Register in global name table 384977cb4d3eSLandon J. Fuller _g_var_names[_name] = _var 385077cb4d3eSLandon J. Fuller 385177cb4d3eSLandon J. Fuller # Add to our parent context 385277cb4d3eSLandon J. Fuller _var_list = get(_ctx, p_vars) 385377cb4d3eSLandon J. Fuller array_append(_var_list, _var) 385477cb4d3eSLandon J. Fuller 385577cb4d3eSLandon J. Fuller # Push our variable definition block 385677cb4d3eSLandon J. Fuller parser_state_open_block(_var) 385777cb4d3eSLandon J. Fuller} 385877cb4d3eSLandon J. Fuller 385977cb4d3eSLandon J. Fuller 386077cb4d3eSLandon J. Fuller# 386177cb4d3eSLandon J. Fuller# Return a string containing the human-readable list of valid Fmt names 386277cb4d3eSLandon J. Fuller# 386377cb4d3eSLandon J. Fullerfunction fmt_get_human_readable_list(_result, _fmts, _fmt, _nfmts, _i) 386477cb4d3eSLandon J. Fuller{ 386577cb4d3eSLandon J. Fuller # Build up a string listing the valid formats 386677cb4d3eSLandon J. Fuller _fmts = map_to_array(ValueFormats) 386777cb4d3eSLandon J. Fuller _result = "" 386877cb4d3eSLandon J. Fuller 386977cb4d3eSLandon J. Fuller _nfmts = array_size(_fmts) 387077cb4d3eSLandon J. Fuller for (_i = 0; _i < _nfmts; _i++) { 387177cb4d3eSLandon J. Fuller _fmt = array_get(_fmts, _i) 387277cb4d3eSLandon J. Fuller if (_i+1 == _nfmts) 387377cb4d3eSLandon J. Fuller _result = _result "or " 387477cb4d3eSLandon J. Fuller 387577cb4d3eSLandon J. Fuller _result = _name_str \ 387677cb4d3eSLandon J. Fuller "'" get(_fmt, p_name) "'" 387777cb4d3eSLandon J. Fuller 387877cb4d3eSLandon J. Fuller if (_i+1 < _nfmts) 387977cb4d3eSLandon J. Fuller _result = _result ", " 388077cb4d3eSLandon J. Fuller } 388177cb4d3eSLandon J. Fuller 388277cb4d3eSLandon J. Fuller obj_delete(_fmts) 388377cb4d3eSLandon J. Fuller return (_result) 388477cb4d3eSLandon J. Fuller} 388577cb4d3eSLandon J. Fuller 388677cb4d3eSLandon J. Fuller# 388777cb4d3eSLandon J. Fuller# Parse a variable parameter from the current line 388877cb4d3eSLandon J. Fuller# 388977cb4d3eSLandon J. Fuller# fmt (decimal|hex|macaddr|...) 389077cb4d3eSLandon J. Fuller# all1 ignore 389177cb4d3eSLandon J. Fuller# desc "quoted string" 389277cb4d3eSLandon J. Fuller# help "quoted string" 389377cb4d3eSLandon J. Fuller# 389477cb4d3eSLandon J. Fullerfunction parse_variable_param(param_name, _var, _vprops, _prop_id, _pval) { 389577cb4d3eSLandon J. Fuller _var = parser_state_get_context(Var) 389677cb4d3eSLandon J. Fuller 389777cb4d3eSLandon J. Fuller if (param_name == "fmt") { 389877cb4d3eSLandon J. Fuller debug($1 " " $2) 389977cb4d3eSLandon J. Fuller 390077cb4d3eSLandon J. Fuller # Check for an existing definition 390177cb4d3eSLandon J. Fuller if ((_pval = get(_var, p_fmt)) != null) { 390277cb4d3eSLandon J. Fuller error("fmt previously specified on line " \ 390377cb4d3eSLandon J. Fuller obj_get_prop_nr(_var, p_fmt)) 390477cb4d3eSLandon J. Fuller } 390577cb4d3eSLandon J. Fuller 390677cb4d3eSLandon J. Fuller # Validate arguments 390777cb4d3eSLandon J. Fuller if (NF != 2) { 390877cb4d3eSLandon J. Fuller error("'" $1 "' requires a single parameter value of " \ 390977cb4d3eSLandon J. Fuller fmt_get_human_readable_list()) 391077cb4d3eSLandon J. Fuller } 391177cb4d3eSLandon J. Fuller 391277cb4d3eSLandon J. Fuller if ((_pval = fmt_named($2)) == null) { 391377cb4d3eSLandon J. Fuller error("'" $1 "' value '" $2 "' unrecognized. Must be " \ 391477cb4d3eSLandon J. Fuller "one of " fmt_get_human_readable_list()) 391577cb4d3eSLandon J. Fuller } 391677cb4d3eSLandon J. Fuller 391777cb4d3eSLandon J. Fuller # Set fmt reference 391877cb4d3eSLandon J. Fuller set(_var, p_fmt, _pval) 391977cb4d3eSLandon J. Fuller } else if (param_name == "all1") { 392077cb4d3eSLandon J. Fuller debug($1 " " $2) 392177cb4d3eSLandon J. Fuller 392277cb4d3eSLandon J. Fuller # Check for an existing definition 392377cb4d3eSLandon J. Fuller if ((_pval = get(_var, p_ignall1)) != null) { 392477cb4d3eSLandon J. Fuller error("all1 previously specified on line " \ 392577cb4d3eSLandon J. Fuller obj_get_prop_nr(_var, p_ignall1)) 392677cb4d3eSLandon J. Fuller } 392777cb4d3eSLandon J. Fuller 392877cb4d3eSLandon J. Fuller # Check argument 392977cb4d3eSLandon J. Fuller if (NF != 2) 393077cb4d3eSLandon J. Fuller error("'" $1 "'requires a single 'ignore' argument") 393177cb4d3eSLandon J. Fuller else if ($2 != "ignore") 393277cb4d3eSLandon J. Fuller error("unknown "$1" value '"$2"', expected 'ignore'") 393377cb4d3eSLandon J. Fuller 393477cb4d3eSLandon J. Fuller # Set variable property 393577cb4d3eSLandon J. Fuller set(_var, p_ignall1, 1) 393677cb4d3eSLandon J. Fuller } else if (param_name == "desc" || param_name == "help") { 393777cb4d3eSLandon J. Fuller # Fetch an indirect property reference for either the 'desc' 393877cb4d3eSLandon J. Fuller # or 'help' property 393977cb4d3eSLandon J. Fuller _prop_id = obj_get_named_prop_id(_var, param_name) 394077cb4d3eSLandon J. Fuller 394177cb4d3eSLandon J. Fuller # Check for an existing definition 394277cb4d3eSLandon J. Fuller if ((_pval = prop_get(_var, _prop_id)) != null) { 394377cb4d3eSLandon J. Fuller error(get(_var, p_name) " '" $1 "' redefined " \ 394477cb4d3eSLandon J. Fuller "(previously defined on line " \ 394577cb4d3eSLandon J. Fuller obj_get_prop_id_nr(_var, _prop_id) ")") 394677cb4d3eSLandon J. Fuller } 394777cb4d3eSLandon J. Fuller 394877cb4d3eSLandon J. Fuller # Seek to the start of the desc/help string 394977cb4d3eSLandon J. Fuller shiftf(1) 395077cb4d3eSLandon J. Fuller 395177cb4d3eSLandon J. Fuller # Parse the first line 395277cb4d3eSLandon J. Fuller _pval = stringconstant_parse_line($0) 395377cb4d3eSLandon J. Fuller 395477cb4d3eSLandon J. Fuller # Incrementally parse line continuations 395577cb4d3eSLandon J. Fuller while (get(_pval, p_continued)) { 395677cb4d3eSLandon J. Fuller getline 395777cb4d3eSLandon J. Fuller stringconstant_append_line(_pval, $0) 395877cb4d3eSLandon J. Fuller } 395977cb4d3eSLandon J. Fuller 396077cb4d3eSLandon J. Fuller debug(param_name " \"" get(_pval, p_value) "\"") 396177cb4d3eSLandon J. Fuller 396277cb4d3eSLandon J. Fuller # Add to the var object 396377cb4d3eSLandon J. Fuller prop_set(_var, _prop_id, _pval) 3964e83ce340SAdrian Chadd } else { 396577cb4d3eSLandon J. Fuller error("unknown variable property type: '" param_name "'") 3966e83ce340SAdrian Chadd } 396777cb4d3eSLandon J. Fuller} 3968e83ce340SAdrian Chadd 396977cb4d3eSLandon J. Fuller 397077cb4d3eSLandon J. Fuller# 397177cb4d3eSLandon J. Fuller# Parse a top-level SROM layout block starting at the current line 397277cb4d3eSLandon J. Fuller# 397377cb4d3eSLandon J. Fuller# srom 4-7 { 397477cb4d3eSLandon J. Fuller# 0x000: ... 397577cb4d3eSLandon J. Fuller# } 397677cb4d3eSLandon J. Fuller# 397777cb4d3eSLandon J. Fullerfunction parse_srom_layout(_nvram, _srom_layouts, _revs, _layout) { 397877cb4d3eSLandon J. Fuller _nvram = parser_state_get_context(NVRAM) 397977cb4d3eSLandon J. Fuller _srom_layouts = get(_nvram, p_srom_layouts) 398077cb4d3eSLandon J. Fuller 398177cb4d3eSLandon J. Fuller # Parse revision descriptor and register SROM 398277cb4d3eSLandon J. Fuller # instance 398377cb4d3eSLandon J. Fuller _revs = parse_revrange() 398477cb4d3eSLandon J. Fuller _layout = srom_layout_new(_revs) 398577cb4d3eSLandon J. Fuller nvram_add_srom_layout(_nvram, _layout) 398677cb4d3eSLandon J. Fuller 398777cb4d3eSLandon J. Fuller debug("srom " revrange_to_string(_revs) " {") 398877cb4d3eSLandon J. Fuller 398977cb4d3eSLandon J. Fuller # Push new SROM parser state 399077cb4d3eSLandon J. Fuller parser_state_open_block(_layout) 399177cb4d3eSLandon J. Fuller} 399277cb4d3eSLandon J. Fuller 399377cb4d3eSLandon J. Fuller 399477cb4d3eSLandon J. Fuller# 399577cb4d3eSLandon J. Fuller# Parse a nested srom range filter block starting at the current line 399677cb4d3eSLandon J. Fuller# srom 4-7 { 399777cb4d3eSLandon J. Fuller# # Filter block 399877cb4d3eSLandon J. Fuller# srom 5 { 399977cb4d3eSLandon J. Fuller# 0x000: ... 400077cb4d3eSLandon J. Fuller# } 400177cb4d3eSLandon J. Fuller# } 400277cb4d3eSLandon J. Fuller# 400377cb4d3eSLandon J. Fullerfunction parse_srom_layout_filter(_parent, _revs, _filter) { 400477cb4d3eSLandon J. Fuller _parent = parser_state_get_context(SromLayout) 400577cb4d3eSLandon J. Fuller 400677cb4d3eSLandon J. Fuller # Parse revision descriptor 400777cb4d3eSLandon J. Fuller _revs = parse_revrange() 400877cb4d3eSLandon J. Fuller 400977cb4d3eSLandon J. Fuller # Construct the filter (which also validates the revision range) 401077cb4d3eSLandon J. Fuller _filter = srom_layout_filter_new(_parent, _revs) 401177cb4d3eSLandon J. Fuller 401277cb4d3eSLandon J. Fuller debug("srom " revrange_to_string(_revs) " {") 401377cb4d3eSLandon J. Fuller 401477cb4d3eSLandon J. Fuller # Push new SROM parser state 401577cb4d3eSLandon J. Fuller parser_state_open_block(_filter) 401677cb4d3eSLandon J. Fuller} 401777cb4d3eSLandon J. Fuller 401877cb4d3eSLandon J. Fuller 401977cb4d3eSLandon J. Fuller# 402077cb4d3eSLandon J. Fuller# Parse a SROM offset segment's attribute list from the current line 402177cb4d3eSLandon J. Fuller# 402277cb4d3eSLandon J. Fuller# <empty line> 402377cb4d3eSLandon J. Fuller# (&0xF0, >>4, =0x5340) 402477cb4d3eSLandon J. Fuller# () 402577cb4d3eSLandon J. Fuller# 402677cb4d3eSLandon J. Fuller# Attribute designators: 402777cb4d3eSLandon J. Fuller# &0xF Mask value with 0xF 402877cb4d3eSLandon J. Fuller# <<4 Shift left 4 bits 402977cb4d3eSLandon J. Fuller# >>4 Shift right 4 bits 403077cb4d3eSLandon J. Fuller# =0x53 The parsed value must be equal to this constant value 403177cb4d3eSLandon J. Fuller# 403277cb4d3eSLandon J. Fuller# May be followed by a | indicating that this segment should be OR'd with the 403377cb4d3eSLandon J. Fuller# segment that follows, or a terminating , indicating that a new offset's 403477cb4d3eSLandon J. Fuller# list of segments may follow. 403577cb4d3eSLandon J. Fuller# 403677cb4d3eSLandon J. Fullerfunction parse_srom_segment_attributes(offset, type, _attrs, _num_attr, _attr, 403777cb4d3eSLandon J. Fuller _mask, _shift, _value, _i) 403877cb4d3eSLandon J. Fuller{ 403977cb4d3eSLandon J. Fuller # seek to offset (attributes...) or end of the offset expr (|,) 4040e83ce340SAdrian Chadd sub("^[^,(|){}]+", "", $0) 4041e83ce340SAdrian Chadd 404277cb4d3eSLandon J. Fuller # defaults 404377cb4d3eSLandon J. Fuller _mask = type_get_default_mask(type) 404477cb4d3eSLandon J. Fuller _shift = 0 4045e83ce340SAdrian Chadd 404677cb4d3eSLandon J. Fuller # parse attributes 4047e83ce340SAdrian Chadd if ($1 ~ "^\\(") { 4048e83ce340SAdrian Chadd # extract attribute list 404977cb4d3eSLandon J. Fuller if (match($0, /\([^|\(\)]*\)/) <= 0) 4050e83ce340SAdrian Chadd error("expected attribute list") 4051e83ce340SAdrian Chadd 405277cb4d3eSLandon J. Fuller _attrs = substr($0, RSTART+1, RLENGTH-2) 405377cb4d3eSLandon J. Fuller 405477cb4d3eSLandon J. Fuller # drop attribute list from the input line 4055e83ce340SAdrian Chadd $0 = substr($0, RSTART+RLENGTH, length($0) - RSTART+RLENGTH) 4056e83ce340SAdrian Chadd 4057e83ce340SAdrian Chadd # parse attributes 405877cb4d3eSLandon J. Fuller _num_attr = split(_attrs, _g_attrs, ",[ \t]*") 405977cb4d3eSLandon J. Fuller for (_i = 1; _i <= _num_attr; _i++) { 406077cb4d3eSLandon J. Fuller _attr = _g_attrs[_i] 406177cb4d3eSLandon J. Fuller 406277cb4d3eSLandon J. Fuller if (sub("^&[ \t]*", "", _attr) > 0) { 406377cb4d3eSLandon J. Fuller _mask = parse_uint_string(_attr) 406477cb4d3eSLandon J. Fuller } else if (sub("^<<[ \t]*", "", _attr) > 0) { 406577cb4d3eSLandon J. Fuller _shift = - parse_uint_string(_attr) 406677cb4d3eSLandon J. Fuller } else if (sub("^>>[ \t]*", "", _attr) > 0) { 406777cb4d3eSLandon J. Fuller _shift = parse_uint_string(_attr) 406877cb4d3eSLandon J. Fuller } else if (sub("^=[ \t]*", "", _attr) > 0) { 406977cb4d3eSLandon J. Fuller _value = _attr 4070e83ce340SAdrian Chadd } else { 407177cb4d3eSLandon J. Fuller error("unknown attribute '" _attr "'") 4072e83ce340SAdrian Chadd } 4073e83ce340SAdrian Chadd } 4074e83ce340SAdrian Chadd } 4075e83ce340SAdrian Chadd 407677cb4d3eSLandon J. Fuller return (srom_segment_new(offset, type, _mask, _shift, _value)) 4077e83ce340SAdrian Chadd} 4078e83ce340SAdrian Chadd 407977cb4d3eSLandon J. Fuller# 408077cb4d3eSLandon J. Fuller# Parse a SROM offset's segment declaration from the current line 408177cb4d3eSLandon J. Fuller# 408277cb4d3eSLandon J. Fuller# +0x0: u8 (&0xF0, >>4) # read 8 bits at +0x0 (relative to srom entry 408377cb4d3eSLandon J. Fuller# # offset, apply 0xF0 mask, shift >> 4 408477cb4d3eSLandon J. Fuller# 0x10: u8 (&0xF0, >>4) # identical to above, but perform the read at 408577cb4d3eSLandon J. Fuller# # absolute offset 0x10 408677cb4d3eSLandon J. Fuller# 408777cb4d3eSLandon J. Fuller# +0x0: u8 # no attributes 408877cb4d3eSLandon J. Fuller# 0x10: u8 408977cb4d3eSLandon J. Fuller# 409077cb4d3eSLandon J. Fuller# +0x0 # simplified forms denoted by lack of ':'; the 409177cb4d3eSLandon J. Fuller# 0x0 # type is inherited from the parent SromEntry 409277cb4d3eSLandon J. Fuller# 409377cb4d3eSLandon J. Fuller# 409477cb4d3eSLandon J. Fullerfunction parse_srom_segment(base_offset, base_type, _simple, _type, _type_str, 409577cb4d3eSLandon J. Fuller _offset, _attrs, _num_attr, _attr, _mask, _shift, _off_desc) 409677cb4d3eSLandon J. Fuller{ 409777cb4d3eSLandon J. Fuller # Fetch the offset value 409877cb4d3eSLandon J. Fuller _offset = $1 4099e83ce340SAdrian Chadd 410077cb4d3eSLandon J. Fuller # Offset string must be one of: 410177cb4d3eSLandon J. Fuller # simplified entry: <offset|+reloff> 410277cb4d3eSLandon J. Fuller # Provides only the offset, with the type inherited 410377cb4d3eSLandon J. Fuller # from the original variable definition 410477cb4d3eSLandon J. Fuller # standard entry: <offset|+reloff>: 410577cb4d3eSLandon J. Fuller # Provides the offset, followed by a type 410677cb4d3eSLandon J. Fuller # 410777cb4d3eSLandon J. Fuller # We differentiate the two by looking for (and simultaneously removing) 410877cb4d3eSLandon J. Fuller # the trailing ':' 410977cb4d3eSLandon J. Fuller if (!sub(/:$/, "", _offset)) 411077cb4d3eSLandon J. Fuller _simple = 1 4111e83ce340SAdrian Chadd 411277cb4d3eSLandon J. Fuller # The offset may either be absolute (e.g. 0x180) or relative (e.g. 411377cb4d3eSLandon J. Fuller # +0x01). 411477cb4d3eSLandon J. Fuller # 411577cb4d3eSLandon J. Fuller # If we find a relative offset definition, we must trim the leading '+' 411677cb4d3eSLandon J. Fuller # and then add the base offset 411777cb4d3eSLandon J. Fuller if (sub(/^\+/, "", _offset)) { 411877cb4d3eSLandon J. Fuller _offset = base_offset + parse_uint_offset(_offset) 411977cb4d3eSLandon J. Fuller } else { 412077cb4d3eSLandon J. Fuller 412177cb4d3eSLandon J. Fuller _offset = parse_uint_offset(_offset) 412277cb4d3eSLandon J. Fuller } 412377cb4d3eSLandon J. Fuller 412477cb4d3eSLandon J. Fuller # If simplified form, use the base type of the SROM entry. Otherwise, 412577cb4d3eSLandon J. Fuller # we need to parse the type. 412677cb4d3eSLandon J. Fuller if (_simple) { 412777cb4d3eSLandon J. Fuller _type = base_type 412877cb4d3eSLandon J. Fuller } else { 412977cb4d3eSLandon J. Fuller _type_str = $2 413077cb4d3eSLandon J. Fuller sub(/,$/, "", _type_str) # trim trailing ',', if any 413177cb4d3eSLandon J. Fuller 413277cb4d3eSLandon J. Fuller if ((_type = parse_type_string(_type_str)) == null) 413377cb4d3eSLandon J. Fuller error("unknown type '" _type_str "'") 413477cb4d3eSLandon J. Fuller } 413577cb4d3eSLandon J. Fuller 413677cb4d3eSLandon J. Fuller # Parse the trailing (... attributes ...), if any 413777cb4d3eSLandon J. Fuller return (parse_srom_segment_attributes(_offset, _type)) 413877cb4d3eSLandon J. Fuller} 413977cb4d3eSLandon J. Fuller 414077cb4d3eSLandon J. Fuller# 414177cb4d3eSLandon J. Fuller# Parse a SROM variable entry from the current line 414277cb4d3eSLandon J. Fuller# <offset>: <type> <varname><array spec> ... 414377cb4d3eSLandon J. Fuller# 414477cb4d3eSLandon J. Fullerfunction parse_srom_variable_entry(_srom, _srom_revs, _rev_start, _rev_end, 414577cb4d3eSLandon J. Fuller _srom_entries, _srom_revmap, _prev_entry, _ctx, _base_offset, _name, 414677cb4d3eSLandon J. Fuller _stype, _var, _entry, _offset, _seg, _i) 414777cb4d3eSLandon J. Fuller{ 414877cb4d3eSLandon J. Fuller # Fetch our parent context 414977cb4d3eSLandon J. Fuller _ctx = parser_state_get_context(SromContext) 415077cb4d3eSLandon J. Fuller _srom_revs = get(_ctx, p_revisions) 415177cb4d3eSLandon J. Fuller _rev_start = get(_srom_revs, p_start) 415277cb4d3eSLandon J. Fuller _rev_end = get(_srom_revs, p_end) 415377cb4d3eSLandon J. Fuller 415477cb4d3eSLandon J. Fuller # Locate our enclosing layout 415577cb4d3eSLandon J. Fuller _srom = parser_state_find_context(SromLayout) 415677cb4d3eSLandon J. Fuller _srom_entries = get(_srom, p_entries) 415777cb4d3eSLandon J. Fuller _srom_revmap = get(_srom, p_revmap) 415877cb4d3eSLandon J. Fuller 415977cb4d3eSLandon J. Fuller # Verify argument count 416077cb4d3eSLandon J. Fuller if (NF < 3) { 416177cb4d3eSLandon J. Fuller error("unrecognized srom entry syntax; must specify at " \ 416277cb4d3eSLandon J. Fuller "least \"<offset>: <type> <variable name>\"") 416377cb4d3eSLandon J. Fuller } 416477cb4d3eSLandon J. Fuller 416577cb4d3eSLandon J. Fuller # Parse the base offset 416677cb4d3eSLandon J. Fuller _base_offset = parse_uint_offset($1) 416777cb4d3eSLandon J. Fuller 416877cb4d3eSLandon J. Fuller # Parse the base type 416977cb4d3eSLandon J. Fuller if ((_stype = type_named($2)) == null) 417077cb4d3eSLandon J. Fuller error("unknown type '" $2 "'") 417177cb4d3eSLandon J. Fuller 417277cb4d3eSLandon J. Fuller # Parse (and trim) any array specifier from the variable name 417377cb4d3eSLandon J. Fuller _name = $3 417477cb4d3eSLandon J. Fuller _stype = parse_array_type_specifier(_name, _stype) 417577cb4d3eSLandon J. Fuller sub(ARRAY_REGEX"$", "", _name) 417677cb4d3eSLandon J. Fuller 417777cb4d3eSLandon J. Fuller # Locate the variable definition 417877cb4d3eSLandon J. Fuller if (!(_name in _g_var_names)) 417977cb4d3eSLandon J. Fuller error("no definition found for variable '" _name "'") 418077cb4d3eSLandon J. Fuller _var = _g_var_names[_name] 418177cb4d3eSLandon J. Fuller 418277cb4d3eSLandon J. Fuller # The SROM entry type must be a subtype of the variable's declared 418377cb4d3eSLandon J. Fuller # type 418477cb4d3eSLandon J. Fuller if (!type_can_represent(get(_var, p_type), _stype)) { 418577cb4d3eSLandon J. Fuller error("'" type_to_string(_stype) "' SROM value cannot be " \ 418677cb4d3eSLandon J. Fuller "coerced to '" type_to_string(get(_var, p_type)) " " _name \ 418777cb4d3eSLandon J. Fuller "' variable") 418877cb4d3eSLandon J. Fuller } 418977cb4d3eSLandon J. Fuller 419077cb4d3eSLandon J. Fuller # Create and register our new offset entry 419177cb4d3eSLandon J. Fuller _entry = srom_entry_new(_var, _srom_revs, _base_offset, _stype) 419277cb4d3eSLandon J. Fuller srom_layout_add_entry(_srom, _entry) 419377cb4d3eSLandon J. Fuller 419477cb4d3eSLandon J. Fuller # Seek to either the block start ('{'), or the attributes to be 419577cb4d3eSLandon J. Fuller # used for a single offset/segment entry at `offset` 419677cb4d3eSLandon J. Fuller shiftf(3) 419777cb4d3eSLandon J. Fuller 419877cb4d3eSLandon J. Fuller # Using the block syntax? */ 419977cb4d3eSLandon J. Fuller if ($1 == "{") { 420077cb4d3eSLandon J. Fuller debug(sprintf("0x%03x: %s %s {", _base_offset, 420177cb4d3eSLandon J. Fuller type_to_string(_stype), _name)) 420277cb4d3eSLandon J. Fuller parser_state_open_block(_entry) 420377cb4d3eSLandon J. Fuller } else { 420477cb4d3eSLandon J. Fuller # Otherwise, we're using the simplified syntax -- create and 420577cb4d3eSLandon J. Fuller # register our implicit SromOffset 420677cb4d3eSLandon J. Fuller _offset = srom_offset_new() 420777cb4d3eSLandon J. Fuller array_append(get(_entry, p_offsets), _offset) 420877cb4d3eSLandon J. Fuller 420977cb4d3eSLandon J. Fuller # Parse and register simplified segment syntax 421077cb4d3eSLandon J. Fuller _seg = parse_srom_segment_attributes(_base_offset, _stype) 421177cb4d3eSLandon J. Fuller array_append(get(_offset, p_segments), _seg) 421277cb4d3eSLandon J. Fuller 421377cb4d3eSLandon J. Fuller debug(sprintf("0x%03x: %s %s { %s }", _base_offset, 421477cb4d3eSLandon J. Fuller type_to_string(_stype), _name, segment_to_string(_seg))) 421577cb4d3eSLandon J. Fuller } 421677cb4d3eSLandon J. Fuller} 421777cb4d3eSLandon J. Fuller 421877cb4d3eSLandon J. Fuller# 421977cb4d3eSLandon J. Fuller# Parse all SromSegment entry segments readable starting at the current line 422077cb4d3eSLandon J. Fuller# 422177cb4d3eSLandon J. Fuller# <offset|+reloff>[,|]? 422277cb4d3eSLandon J. Fuller# <offset|+reloff>: <type>[,|]? 422377cb4d3eSLandon J. Fuller# <offset|+reloff>: <type> (<attributes>)[,|]? 422477cb4d3eSLandon J. Fuller# 422577cb4d3eSLandon J. Fullerfunction parse_srom_entry_segments(_entry, _base_off, _base_type, _offs, 422677cb4d3eSLandon J. Fuller _offset, _segs, _seg, _more_seg, _more_vals) 422777cb4d3eSLandon J. Fuller{ 422877cb4d3eSLandon J. Fuller _entry = parser_state_get_context(SromEntry) 422977cb4d3eSLandon J. Fuller _base_off = get(_entry, p_base_offset) 423077cb4d3eSLandon J. Fuller _offs = get(_entry, p_offsets) 423177cb4d3eSLandon J. Fuller 423277cb4d3eSLandon J. Fuller _base_type = get(_entry, p_type) 423377cb4d3eSLandon J. Fuller _base_type = type_get_base(_base_type) 423477cb4d3eSLandon J. Fuller 423577cb4d3eSLandon J. Fuller # Parse all offsets 4236e83ce340SAdrian Chadd do { 423777cb4d3eSLandon J. Fuller # Create a SromOffset 423877cb4d3eSLandon J. Fuller _offset = srom_offset_new() 423977cb4d3eSLandon J. Fuller _segs = get(_offset, p_segments) 4240e83ce340SAdrian Chadd 424177cb4d3eSLandon J. Fuller array_append(_offs, _offset) 4242e83ce340SAdrian Chadd 424377cb4d3eSLandon J. Fuller # Parse all segments 4244e83ce340SAdrian Chadd do { 424577cb4d3eSLandon J. Fuller _seg = parse_srom_segment(_base_off, _base_type) 424677cb4d3eSLandon J. Fuller array_append(_segs, _seg) 424777cb4d3eSLandon J. Fuller 424877cb4d3eSLandon J. Fuller # Do more segments follow? 4249e83ce340SAdrian Chadd _more_seg = ($1 == "|") 4250e83ce340SAdrian Chadd if (_more_seg) 4251e83ce340SAdrian Chadd shiftf(1, 1) 425277cb4d3eSLandon J. Fuller 425377cb4d3eSLandon J. Fuller if (_more_seg) 425477cb4d3eSLandon J. Fuller debug(segment_to_string(_seg) " |") 425577cb4d3eSLandon J. Fuller else 425677cb4d3eSLandon J. Fuller debug(segment_to_string(_seg)) 4257e83ce340SAdrian Chadd } while (_more_seg) 425877cb4d3eSLandon J. Fuller 425977cb4d3eSLandon J. Fuller # Do more offsets follow? 4260e83ce340SAdrian Chadd _more_vals = ($1 == ",") 4261e83ce340SAdrian Chadd if (_more_vals) 4262e83ce340SAdrian Chadd shiftf(1, 1) 4263e83ce340SAdrian Chadd } while (_more_vals) 4264e83ce340SAdrian Chadd} 4265