# ex:set sw=4 ts=8 wm=0:
# $Header: /dvp1/common/tools/rgd.awk 47    12/06/00 11:35a Bog $
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# (C) Copyright 1996-1998 Philips Semiconductors
# All rights reserved
#
# This source code and any compilation or derivative thereof is the sole
# property of Philips Semiconductors and is provided pursuant to a
# Software License Agreement.  This code is the proprietary information
# of Philips Semiconductors and is confidential in nature.  Its use and
# dissemination by any party other than Philips Semiconductors is
# strictly limited by the confidential information provisions of the
# Agreement referenced above.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# $History: rgd.awk $
# 
# *****************  Version 47  *****************
# User: Bog          Date: 12/06/00   Time: 11:35a
# Updated in $/dvp1/common/tools
# If a val line appears first after a bits line, CollectOut() would print
# the val line rather than the required bit offset.
# 
# *****************  Version 46  *****************
# User: Bog          Date: 00-04-20   Time: 6:27p
# Updated in $/WinFire/inc
# Don't prefix the block name if there's no block.
# 
# *****************  Version 45  *****************
# User: Bog          Date: 00-03-01   Time: 12:53p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rkarge       Date: 2/20/00    Time: 1:34p
# # Updated in $/VMipsInt/Tools
# # Make sure URD files don't use names of more than 30 characters. 
# # Removed double print of #EndRegisterList
# 
# *****************  Version 44  *****************
# User: Bog          Date: 00-03-01   Time: 12:51p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-02-18   Time: 2:22p
# # Updated in $/VMipsInt/Tools
# # Don't put out hierarchy level on bottom level bitfields and bytes.
# 
# *****************  Version 43  *****************
# User: Bog          Date: 00-03-01   Time: 12:50p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-02-17   Time: 2:45p
# # Updated in $/VMipsInt/Tools
# # Seems to do what we want for split URD.
# 
# *****************  Version 42  *****************
# User: Bog          Date: 00-03-01   Time: 12:49p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-02-17   Time: 1:08p
# # Updated in $/VMipsInt/Tools
# # Transient version that ha fully qualified name stuff in URD.
# 
# *****************  Version 41  *****************
# User: Bog          Date: 00-03-01   Time: 12:48p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-02-11   Time: 5:02p
# # Updated in $/VMipsInt/Tools
# # Make urd work for modules, at least for a first pass.  Allow multiple
# # Ids for a module.
# 
# *****************  Version 40  *****************
# User: Bog          Date: 00-03-01   Time: 12:47p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-01-26   Time: 11:27a
# # Updated in $/VMipsInt/Tools
# # Fix up HexValue to use HexDigitValue instead of Ord.
# 
# *****************  Version 39  *****************
# User: Bog          Date: 00-03-01   Time: 12:45p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rkarge       Date: 1/24/00    Time: 4:25p
# # Updated in $/VMipsInt/Tools
# # Added implementation for "Ord" function after feedback from UTV that
# # "ord" was not a built-in function of Unix gawk.
# 
# *****************  Version 38  *****************
# User: Bog          Date: 00-03-01   Time: 12:44p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-01-13   Time: 8:08p
# # Updated in $/VMipsInt/Tools
# # Let -v OutputFormat="urd" be on command line.
# 
# *****************  Version 37  *****************
# User: Bog          Date: 00-03-01   Time: 12:43p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-01-13   Time: 8:05p
# # Updated in $/VMipsInt/Tools
# # Add "module" keyword.
# 
# *****************  Version 36  *****************
# User: Bog          Date: 00-03-01   Time: 12:41p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 00-01-06   Time: 4:31p
# # Updated in $/VMipsInt/Tools
# # Check for and flag any redefinition of a "val" word.
# 
# *****************  Version 35  *****************
# User: Bog          Date: 00-03-01   Time: 12:40p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 99-11-20   Time: 9:13p
# # Updated in $/VMipsInt/inc
# # Initial filler bits in a big endian bitfield dword should be
# anonymous.
# 
# *****************  Version 34  *****************
# User: Bog          Date: 00-03-01   Time: 12:38p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rkarge       Date: 11/06/99   Time: 11:43a
# # Updated in $/VMipsInt/inc
# # Changed URD part to make register and bitfield names unique...
# 
# *****************  Version 33  *****************
# User: Bog          Date: 00-03-01   Time: 12:37p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 99-11-05   Time: 1:40p
# # Updated in $/VMipsInt/inc
# # Propagate Coding Guidelines name changes to the offset checking
# # gadgetry.
# 
# *****************  Version 32  *****************
# User: Bog          Date: 00-03-01   Time: 12:35p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 99-11-05   Time: 12:10p
# # Updated in $/VMipsInt/inc
# # A bits or bytes declaration was changing Name to include the prefix
# if
# # a blockname prefix was being added.  This led to the name not being
# # found on a subsequent use of the Name as a type.
# # 
# # We now use the PrefixName in the type, but leave Name alone.
# 
# *****************  Version 31  *****************
# User: Bog          Date: 00-03-01   Time: 12:34p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 99-10-29   Time: 4:54p
# # Updated in $/VMipsInt/inc
# # Add "s" or "u" prefix to bitfields so we can have signed fields:
# #   s 25:04 stride         // signed stride in bytes
# 
# *****************  Version 30  *****************
# User: Bog          Date: 00-03-01   Time: 12:32p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Bog          Date: 99-10-27   Time: 3:45p
# # Updated in $/VMipsInt/inc
# # In blocks, put out typedef name according to new coding guidelines:
# # <name>_t instead of t<name>.
# 
# *****************  Version 29  *****************
# User: Bog          Date: 00-03-01   Time: 12:29p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rkarge       Date: 10/25/99   Time: 5:46p
# # Updated in $/VMipsInt/inc
# # Checked in Ronald's last changes to create an output file for the URD
# # if "OutputFormat=urd".
# 
# *****************  Version 28  *****************
# User: Bog          Date: 00-03-01   Time: 12:27p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rsloot       Date: 9/14/99    Time: 11:52a
# # Updated in $/viper
# # The awk script now assumes the block name is also the prefix
# # used in the register names... This makes it possible to declare
# # copies of the registers on the stack using the convention
# # union _<fieldname>.
# # 
# # Previously one had to use union _<blockname>_<fieldname>
# # which caused duplicates of the blocknames in the union names
# # if the fieldname included the blockname.
# 
# *****************  Version 27  *****************
# User: Bog          Date: 00-03-01   Time: 12:26p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rsloot       Date: 8/16/99    Time: 1:49p
# # Updated in $/viper
# # Union names for BITS/BYTES got prefixed with module name. Fixed.
# 
# *****************  Version 26  *****************
# User: Bog          Date: 00-03-01   Time: 12:24p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rsloot       Date: 8/03/99    Time: 10:55a
# # Updated in $/viper
# # Necessary changes to process a RGD file for VIPER and ISI compiler.
# # - Catchup now splits up filler arrays of size larger than 0x80000000.
# # Some compilers (e.g. DIAB) can't handle those.
# # - In order to deal with externally defined simple types and their
# # re-use
# # in the RGD file (e.g. UINT32 in the DvpTypes.h file), the keyword 
# # 'exttypedef' got added (for simple typedefs). This simply won't emit
# # the 'typedef ...' line in the RGD file and therefore relies on a
# # definition
# # done earlier in an include file. This way we can use the 'DvpTypes.h'
# # file.
# # - IsRegisterName now prefixes created unions from the 'bits' and
# # 'bytes'
# # constructs to prevent name clashes (e.g. _ctrl being used multiple
# # times
# # within the same block). The prefix used is the blockname.
# 
# *****************  Version 25  *****************
# User: Bog          Date: 00-03-01   Time: 12:23p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rsloot       Date: 7/12/99    Time: 11:58a
# # Updated in $/viper
# # Corrected bodystring. Needed extra %s.
# 
# *****************  Version 24  *****************
# User: Bog          Date: 00-03-01   Time: 12:20p
# Updated in $/WinFire/Wince212_beta1/PLATFORM/tvpak_cepc/inc
# Merged branches:
# # User: Rsloot       Date: 6/15/99    Time: 5:07p
# # Created in $/viper
# # Initial dvp3218 (Viper) RGD files.
# 
# *****************  Version 23  *****************
# User: Rsloot       Date: 4/26/99    Time: 7:58p
# Updated in $/jedi
# Construct
#   bytes XXXX
#                   0   Byte[4]
# not correctly handled when BigEndian=1. Fixed in CollectOut ()
# and "bytes" processor. Now keeps track of last "bytes"
# construct size in "BytesCount".
# 
# *****************  Version 22  *****************
# User: Rsloot       Date: 4/14/99    Time: 2:26p
# Updated in $/jedi
# Added bigendian support. By default the script runs in little
# endian mode. Setting the BigEndian boolean variable to '1'
# enables big endian mode, e.g.
#    rgd.exe BigEndian=1 9730.rgd >9730.mio
# 
# *****************  Version 21  *****************
# User: Glydon       Date: 4/06/99    Time: 5:23p
# Updated in $/WinCEProjects/WinCE211/PLATFORM/CEMIPS/INC
# Update for Lee's change: Added #ifndef <filename>/#endif derived from
# "file" keyword to eliminate multiple header file include problem.
# 
# *****************  Version 20  *****************
# User: Bog_wd       Date: 98-10-09   Time: 9:29a
# Updated in $/WinCEProjects/WepCE210/Platform/CEPC/INC
# 1.  Remove the extra "volatile" from PP9730.
# 2.  Add offset checking code to ensure that the offsets of the structs
# are what we theink they are.
# 3.  Clean up number parsing.  Add various hex and decimal formats.
# 
# *****************  Version 19  *****************
# User: Bog_wd       Date: 98-10-07   Time: 4:51p
# Updated in $/WinCEProjects/WepCE210/Platform/CEPC/INC
# Disallow embedded structs and unions that have a tag but no name.  In
# C++, they are seen as type declarations that reserve no storage; in C
# they reserve storage.
# 
# *****************  Version 18  *****************
# User: Bog_wd       Date: 98-10-02   Time: 2:30p
# Updated in $/WinCEProjects/WepCE210/Platform/CEPC/INC
# Allow dimensions to be specified in hex.
# 
# *****************  Version 17  *****************
# User: Bog_wd       Date: 98-09-18   Time: 2:50p
# Updated in $/WinCEProjects/WepCE210/Platform/CEPC/INC
# Add typedef volatile struct P9730 * volatile PP9730 so we get enough
# volatility.
# 
# *****************  Version 16  *****************
# User: Bog_wd       Date: 98-07-17   Time: 5:05p
# Updated in $/jedi
# 1.  Add "previous", like typedef.
# 2.  Put out "volatile" in typedef.
# 
# *****************  Version 15  *****************
# User: Bog_wd       Date: 98-07-17   Time: 9:56a
# Updated in $/jedi
# Fix tabbing.
# 
# *****************  Version 14  *****************
# User: Bog_wd       Date: 98-06-26   Time: 4:41p
# Updated in $/jedi
# Add doc for "blocks".
# 
# *****************  Version 13  *****************
# User: Bog_wd       Date: 98-06-18   Time: 11:06a
# Updated in $/jedi
# Outer blocks should start current location counter at 0.
# 
# *****************  Version 12  *****************
# User: Bog_wd       Date: 98-06-03   Time: 3:10p
# Updated in $/jedi
# "Jedi" -> "P9730".  Add "blocks" bracket.
# 
# *****************  Version 11  *****************
# User: Bog_wd       Date: 98-06-03   Time: 11:48a
# Updated in $/jedi
# Put out
#  #define blkJedi<hex block number>  <block name>
# for table building.
# 
# *****************  Version 10  *****************
# User: Bog_wd       Date: 98-05-08   Time: 1:20p
# Updated in $/jedi
# If DEBUG, it should still be usable.
# 
# *****************  Version 9  *****************
# User: Bog_wd       Date: 98-04-30   Time: 4:11p
# Updated in $/jedi
# Clean up style.
# 
# *****************  Version 8  *****************
# User: Bog_wd       Date: 98-04-29   Time: 1:32p
# Updated in $/jedi
# LAN done.  ItemFromType[] implemented.
# 
# *****************  Version 7  *****************
# User: Bog_wd       Date: 98-04-29   Time: 9:49a
# Updated in $/jedi
# Seems to work.
# 
# *****************  Version 6  *****************
# User: Bog_wd       Date: 98-04-24   Time: 6:07p
# Updated in $/jedi
# Changed "predefined" to "typedef".  Still a minor problem to chase.
#
# *****************  Version 5  *****************
# User: Bog_wd       Date: 98-04-24   Time: 2:06p
# Updated in $/jedi
# Transient checkin.  Changing "predefined" stuff.
#
# *****************  Version 4  *****************
# User: Bog_wd       Date: 98-04-23   Time: 8:30p
# Updated in $/jedi
# Add comments.  Clean up.
#
# *****************  Version 3  *****************
# User: Bog_wd       Date: 98-04-22   Time: 2:49p
# Updated in $/jedi
# Reorganize.  Allow structs and unions.
#
# *****************  Version 2  *****************
# User: Bog_wd       Date: 98-04-22   Time: 2:48p
# Updated in $/jedi
# Interim.
#
# *****************  Version 1  *****************
# User: Bog_wd       Date: 98-04-15   Time: 11:29a
# Created in $/jedi
# Jedi register declarations processor
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
#  This file is used to process the 9730 register delcarations.
#
#  The declarations are converted by the translator program into a
#  C++ .h file that is included in the P9730 struct in our builds.
#
#  We could, if needed, convert this into other formats, too.
#
#
#  Syntax
#  ------
#
#  The file's syntax is line oriented.  Each line is a particular kind
#  of line, determined either by a keyword or by context.  Each kind of
#  line has an expected format, with fields in a particular order.
#
#  The register declarations are dword oriented because that't the way
#  the hardware is oriented.
#
#  At the bottom, each dword register is declared to be
#    - a structure from a known typedef,
#    - a bitfield structure,
#    - a 4 byte structure, or
#    - a previously declared dword register.
#
#  After processing, every dword is in a union with another variable,
#  the dword "dw".  You can use the "dw" variable to read or write
#  dwords at a time, avoiding field manipulation over the slow PCI bus.
#
#
#  Comments
#  --------
#
#    Syntax:
#
#      // <anything>
#
#    Example:
#
#      // this is a comment
#
#    The translator ignores anything from "//" to the end of a line.
#
#
#  typedefs
#  --------
#
#    Syntax:
#
#      typedef <type stuff> <name> [<dimensions>] ; // simple typedef
#
#      typedef {struct|union} {                     // complex typedef
#          ... whatever ...
#      } <name> [<dimensions>] ;
#
#    Examples:
#
#      typedef unsigned long U32;
#
#      typedef union {
#        unsigned long u32;
#        unsigned short u16;
#        unsigned char u8;
#      } COLOR32;
#
#    Once a typedef is declared, it can be used to later declare dword
#    registers.  The translator doesn't pay attention to the internals
#    of typedefs; it just remembers the names (and dimensions, if any)
#    for later use.
#
#    Simple typedefs are copied to the .h file by the translator.  They
#    are assumed to boil down to a dword or arrays of dwords.  The
#    translator knows about the dimensions on the simple dword, so it
#    can keep track of how big any later dword array is, even if it is
#    also dimensioned.
#
#    Complex typedefs are copied in modified form, with a union giving
#    access to a "dw" member.  The above complex typedef example is
#    tranformed to:
#
#      typedef union {
#          union {
#              unsigned long  u32;
#              unsigned short u16;
#              unsigned char  u8;
#          };
#          volatile unsigned long dw;
#      } COLOR32 ;
#
#    Once you've declared a typedef, you can use it later to declare
#    dwords.  An example:
#
#      COLOR32    CompareColor         0141c // color to which we compare
#
#    This declares "CompareColor" to be a dword of structure COLOR32 at
#    hex offset 0141c in the 9730 address aperture.
#
#
#  Bitfield structures
#  -------- ----------
#
#    Syntax:
#
#      bits <bitfield struct name> [<dimensions>] <offset>
#        [s|u] [[msb]:]lsb] <bitfield name>
#          val <value name> <value>
#
#    Example:
#
#      bits       VIPPattGenCtl        00804
#      s 09:00      TPGYS                    // vert window size
#        25:16      TPGXS                    // horiz window size
#           28      HSEL                     // horizontal timing sig select
#             val     HSEL_GenHREF         0 //   generate HREF
#             val     HSEL_GenHS           1 //   generate HS
#           29      VSEL                     // vertical timing signal select
#             val     VSEL_GenVREF         0 //   generate VREF
#             val     VSEL_GenHS           1 //   generate VS
#           30      NSTD                     // use 0=standard timing
#           31      PAL                      // 0=NTSC, 1=PAL timing
#
#    The translator generates a union with the tag _<name> so you can
#    declare locals of that type.
#
#    Bitfields within the structure are declared by giving their bit
#    positions in an [s|u] [[msb]:]lsb decimal format.  For example,
#    "25:16" refers to 25 through 16 of the dword.  "16" or ":16" both
#    refer to the single bit at position 16.  "s 25:16" makes a signed
#    field; "u 25:16" or just plain "25:16" means unsigned.
#
#    You can declare #define symbols and their values, too.  In the
#    above example, the line
#
#             val     HSEL_GenHS           1 //   generate HS
#
#    generates
#
#      #define HSEL_GenHS 1
#
#    and one would expect it to be used in something like
#
#      P9730::_VIPPattGenCtl VIPPattGenCtl;
#
#      VIPPattGenCtl.TPGYS = 47;
#      VIPPattGenCtl.HSel = HSel_GenHS;
#
#      p9730Regs->VIPPattGenCtl.dw = VIPPattGenCtl.dw;// single dword write
#
#    Note that the temporary on the stack gets the inefficient
#    xor/and/xor field manipulation, but the PCI bus gets a single
#    write, without losing the "volatile" attribute.
#
#
#  4 byte structures
#  - ---- ----------
#
#    Syntax:
#
#      bytes <byte struct name> [<dimensions>] <offset>
#          <byte number> <byte name> [<dimension>]
#
#    Example:
#
#      bytes      Color[256]           00400 // memory mapped access to palette
#            0      Blue                     // blue component
#            1      Green                    // green component
#            2      Red                      // red component
#            3      Addr                     // address 00..ff of ramdac entry
#
#    Use this when you are declaring a dword of 4 bytes.
#
#    It starts out with the "bytes" keyword, followed by the name of
#    the structure and the hex offset in the 9730 address aperture.
#
#    Note that dword structure names can have dimensions on them.  So
#    can any other line that allocates address space.
#
#    The individual named bytes have their decimal byte-within-dword
#    offsets followed by the byte name.
#
#
#  Previously Declared Dword Register
#  ---------- -------- ----- --------
#
#    Syntax:
#
#      <previous name> <name> [<dimensions>] <offset>
#
#    Example:
#
#      bits       ICPHBlank            01004
#        11:00      End                      // horizontal blank start
#        27:16      Start                    // horizontal blank start
#      ICPHBlank  ICPVBlank            01008 // vertical blank
#      ICPHBlank  ICPHSync             0100c // horizontal sync
#
#    Once you have declared a particular dword register, you can use
#    its definition in a later declaration as long as the original
#    definition is visible in its nesting scope.  The example
#    translates to:
#
#      volatile union _ICPHBlank {
#          volatile struct {
#              volatile unsigned long End : 12;
#              unsigned long : 4;
#              volatile unsigned long Start : 12;
#          };
#          volatile unsigned long dw;
#      } ICPHBlank;
#      volatile union _ICPHBlank ICPVBlank;
#      volatile union _ICPHBlank ICPHSync;
#
#
#  Structures and Unions
#  ---------- --- ------
#
#    Syntax:
#
#      struct [tag] { [<offset>]
#        ... whatever ...
#      } <struct name> [<dimensions>] ;
#
#      union [tag] { [<offset>]
#        ... whatever ...
#      } [<union name>] [<dimensions>] ;
#
#    Example:
#
#      union {                         00808
#        bits     VIPSourceStatus      00808 // read: Status; write: Host Write
#          09:00    SVLC                     // source video line count
#             15    SFID                     // source field identifier
#        U32      VIPHostWritePort     00808 // write: video in data
#      };
#
#    This declares VIPSourceStatus and VIPostWritePort as being at the
#    same address.
#
#    Although you must have dword register structures at the bottom,
#    you can have arbitrary structs and unions above them.
#
#    The <tag> is optional, as is the <offset>.  If the <offset> is not
#    present, it is assumed to be the next available location.
#
#    Note the offset on the "union" line.
#
#
#  Padding
#  -------
#
#    The translator will insert filler char arrays as necessary to make
#    the declared dwords and struct/unions line up properly.  So if you
#    have
#
#      bits       VIPVBIWinStop        00824
#        09:00      YVWB                     // vertical VBI window end
#        25:16      XVWB                     // horizontal VBI window end
#
#      bits       VIPScaleIncrOdd      00830
#        11:00      YSCI                     // vertical scaling increment
#        27:16      XSCI                     // horizontal  scaling increment
#
#    the translation will be
#
#      volatile union _VIPVBIWinStop {
#          volatile struct {
#              volatile unsigned long YVWB : 10;
#              unsigned long : 6;
#              volatile unsigned long XVWB : 10;
#          };
#          volatile unsigned long dw;
#      } VIPVBIWinStop;
#      volatile unsigned char filler00828[0x00830-0x00828];
#      volatile union _VIPScaleIncrOdd {
#          volatile struct {
#              volatile unsigned long YSCI : 12;
#              unsigned long : 4;
#              volatile unsigned long XSCI : 12;
#          };
#          volatile unsigned long dw;
#      } VIPScaleIncrOdd;
#
#    The translator inserted the filler00828 to pad to 00830.  Note
#    also the pads in the bitfields themselves.
#
#
#  block
#  -----
#
#    Syntax:
#
#      block <block name> <start offset>..<end offset>
#
#    You can document the various register blocks with "block":
#
#      block    AltRAMDAC       00400..007ff // RAMDAC Registers Alt Access
#
#    This declares "AltRAMDAC" to be a block ranging from hex 00400
#    through 007ff in the 9730 address aperture.  It results in two
#    #defines:
#
#      #define blkAltRAMDAC 0x01
#      #define blkSizeAltRAMDAC 1
#
#    blkAltRAMDAC is the 1kb block number for the AltRAMDAC block, and
#    bl;kSizeAltRAMDAC is the number of 1k chunks in the block.
#
#    No dword register declaration or struct or union can cross a block
#    boundary.
#
#
#  blocks
#  ------
#
#    Syntax:
#
#      blocks <blocks name>
#
#    You can group blocks together into structures.  The "blocks" line
#    starts a struct with tag <blocks name>:
#
#      blocks   P9730
#
#    This starts an enclosing struct P9730.  The struct ends at the
#    next "blocks" line or the end of the file.
#
#    No dword register declaration or struct or union can cross a block
#    boundary.
#
#
#  <dimensions>
#  ------------
#
#  Dimensions are optional.  You can have arrays of dword registers,
#  structures, or unions.  See the ICP Layer[] struct as an example.
#
#  Syntax is like C.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# int HexValue(string)
#
# Return value of hex digit string
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function HexValue(In, Result, t)# local Result, t
{
    Result = 0
    t = In
    while (length(t))
    {
        Result = Result * 16 + HexDigitValue[substr(t, 1, 1)]
        t = substr(t, 2)
    }
    return(Result)
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# int Hex(string)
#
# Return value of digit string, default hex
#
# Hex:
#   [0-9a-f]+[h]
#   0x[0-9a-f]+
#
# Decimal:
#   [0-9]+t
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function Hex(In, L)             # local L
{
    L = tolower(In)
    if (L ~ /^[0-9a-f]+h$/)
    {
        return(HexValue(substr(L, 1, length(L) - 1)))
    }
    else if (L ~ /^0x[0-9a-f]+$/)
    {
        return(HexValue(substr(L, 3)))
    }
    else if (L ~ /^[0-9]+t$/)
    {
        return(0 + substr(L, 1, length(L) - 1))
    }
    else if (L ~ /^[0-9a-f]+$/)
    {
        return(HexValue(L))
    }

    print "!! Hex? " In
    return(0)
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# int IsHex(string)
#
# Return nonzero if the digit string looks like a hex number
#
# Hex:
#   [0-9a-f]+[h]
#   0x[0-9a-f]+
#
# Decimal:
#   [0-9]+t
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function IsHex(In, L)           # local L
{
    L = tolower(In)
    return(L ~ /(^[0-9a-f]+h$)|(^0x[0-9a-f]+$)|(^[0-9]+t$)|(^[0-9a-f]+$)/)
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# int Decimal(string)
#
# Return value of digit string, default decimal
#
# Decimal:
#   [0-9]*[t]
#
# Hex:
#   [0-9a-f]*h
#   0x[0-9a-f]*
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function Decimal(In, L)         # local L
{
    L = tolower(In)
    if (L ~ /^[0-9a-f]+h$/)
    {
        return(HexValue(substr(L, 1, length(L) - 1)))
    }
    else if (L ~ /^0x[0-9a-f]+$/)
    {
        return(HexValue(substr(L, 3)))
    }
    else if (L ~ /^[0-9]+t$/)
    {
        return(0 + substr(L, 1, length(L) - 1))
    }
    else if (L ~ /^[0-9]+$/)
    {
        return(0 + L)
    }

    print "!! Decimal? " In
    return(0)
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# int IsDecimal(string)
#
# Return nonzero if the digit string looks like a decimal number
#
# Decimal:
#   [0-9]*[t]
#
# Hex:
#   [0-9a-f]*h
#   0x[0-9a-f]*
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function IsDecimal(In, L)       # local L
{
    L = tolower(In)
    return(L ~ /(^[0-9a-f]+h$)|(^0x[0-9a-f]+$)|(^[0-9]+t$)|(^[0-9]+$)/)
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# CollectAppend
#
# Appends the string 'In' with the attribute 'KeepOrder' to a table. All the
# strings in the table can be printed later on with the CollectOut() function.
# Set 'KeepOrder' to true (1) when CollectOut() should not change the order
# of this string appended.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function CollectAppend(In, KeepOrder)
{
    NumCollect++
    CollectType[NumCollect] = KeepOrder
    CollectOutput[NumCollect] = In
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# CollectOut
#
# Depending on the endianess this script is running (controlled by the
# BigEndian boolean variable), CollectOut() will output the strings in reversed
# order in which they were appended by the CollectAppend() function.
# Lines which got added with the 'KeepOrder' boolean set to true (1), will be
# output in the order they were added.
#
# If the script is running in little endian mode (BigEndian set to false) the
# strings are output in the order they were appended.
#
# The table in which the strings are kept is emptied after the strings have
# been output.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function CollectOut()
{
    # Output gathered bitfields in big or little endian order
    if (Class == ClassBits)
    {
        if (BigEndian)
        {
            if (Type == "bytes")
            {
                for (i = Byte + BytesCount - 1; i < 3; i++)
                {
                    # skip val lines
                    for (t = 1; CollectType[t]; t++)
                    {
                    }
                    t = CollectOutput[t]
                    sub(                                                      \
                        "[0-9a-zA-Z_]+[\t ]*;",
                        sprintf("_byte%d;", i - Byte),
                        t                                                     \
                    );
                    printf("%s", t)
                }
            }
            if ((CurrentBitLocation > 0) && ((32 - CurrentBitLocation) > 0))
            {
                # skip val lines
                for (t = 1; CollectType[t]; t++)
                {
                }
                t = CollectOutput[t]
                sub(                                                          \
                    "[0-9a-zA-Z_]+[\t ]*:.*",
                    sprintf(": %d;\n", 32 - CurrentBitLocation),
                    t                                                         \
                );
                printf("%s", t)
            }
            for (CollectIdx = NumCollect; CollectIdx >= 1; CollectIdx--)
            {
                if (CollectType[CollectIdx] == 1)
                {
                    # Must preserve order. Find entry at which this order ends.
                    CollectEndIdx = CollectIdx
                    while (CollectIdx >= 1)
                    {
                        if (CollectType[CollectIdx] == 0)
                        {
                            printf CollectOutput[CollectIdx]
                            break
                        }
                        CollectIdx--
                    }
                    CollectStartIdx = CollectIdx
                    CollectIdx++
                    while (CollectIdx <= CollectEndIdx)
                    {
                        printf CollectOutput[CollectIdx]
                        CollectIdx++
                    }
                    CollectIdx = CollectStartIdx
                }
                else
                    printf CollectOutput[CollectIdx]
            }
        }
        else
        {
            for (CollectIdx = 1; CollectIdx <= NumCollect; CollectIdx++)
                printf CollectOutput[CollectIdx]
        }
        NumCollect = 0
    }
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# CreatePlaceholder(
#   Name,                       # Name of new placeholder
#   Class,                      # Class
#   Size,                       # Size
#   Count                       # Count
# )
#
# Create a new Item of Type "placeholder" with given Name, Class, Size
# and Count.
#
# Return Item of the new placeholder.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function CreatePlaceholder(Name, Class, Size, Count)
{
    ItemType       [NextAvail] = "placeholder"
    ItemClass      [NextAvail] = Class
    ItemName       [NextAvail] = Name
    ItemTag        [NextAvail] = ""
    ItemDims       [NextAvail] = ""
    ItemOffset     [NextAvail] = 0
    ItemSize       [NextAvail] = Size
    ItemCount      [NextAvail] = Count
    ItemBitStart   [NextAvail] = -1
    ItemBitEnd     [NextAvail] = -1

    ItemPrevSibling[NextAvail] = 0
    ItemNextSibling[NextAvail] = 0
    ItemFirstChild [NextAvail] = 0
    ItemLastChild  [NextAvail] = 0
    ItemParent     [NextAvail] = 0

    ItemFromType[Name] = NextAvail

    return(NextAvail++)
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Open(NewType)
#
# Begin a new item, of Type NewType.
#
# The current Xxxxglobals are copied into ItemXxx[This].  The new item
# is created as a new Child of This, linked appropriately into the Child
# and Sibling chains.
#
# The Xxxx globals are initialized.
#
# The Offset is set to CurrLoc unless the parent is a union, in which
# case it is set to the parent's Offset.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function Open(NewType)
{
    ItemType       [This] = Type
    ItemClass      [This] = Class
    ItemName       [This] = Name
    ItemTag        [This] = Tag
    ItemDims       [This] = Dims
    ItemOffset     [This] = Offset
    ItemSize       [This] = Size
    ItemCount      [This] = Count
    ItemBitStart   [This] = BitStart
    ItemBitEnd     [This] = BitEnd

    ItemPrevSibling[This] = PrevSibling
    ItemNextSibling[This] = NextSibling
    ItemFirstChild [This] = FirstChild
    ItemLastChild  [This] = LastChild
    ItemParent     [This] = Parent

    Parent = This
    # we're creating a new child of Parent, new sibling of
    # ItemLastChild[Parent]
    This = NextAvail++
    if (PrevSibling = ItemLastChild[Parent])
    {
        # This is not first child of Parent
        ItemNextSibling[PrevSibling] = This
    }
    else {
        # This is first child of Parent
        ItemFirstChild[Parent] = This
    }
    ItemLastChild[Parent] = This
    NextSibling = 0
    FirstChild = 0
    LastChild = 0

    Type = NewType
    Class = ItemClass[ItemFromType[NewType]]
    # if inside union, start Offset over
    if (ItemType[Parent] == "union")
    {
        Offset = ItemOffset[Parent]
    }
    else {
        Offset = CurrLoc
    }
    CurrLoc = Offset
    Name = ""
    Tag = ""
    Dims = ""
    Size = ItemSize[ItemFromType[NewType]]
    Count = ItemCount[ItemFromType[NewType]]
    BitStart = -1
    BitEnd = -1
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Close()
#
# End an item.
#
# The current Xxxx globals are copied into ItemXxx[This].
# ItemXxxx[Parent] are copied into the Xxxx globals and it is made This.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function Close()
{
    ItemType       [This] = Type
    ItemClass      [This] = Class
    ItemName       [This] = Name
    ItemTag        [This] = Tag
    ItemDims       [This] = Dims
    ItemOffset     [This] = Offset
    ItemSize       [This] = Size
    ItemCount      [This] = Count
    ItemBitStart   [This] = BitStart
    ItemBitEnd     [This] = BitEnd

    ItemPrevSibling[This] = PrevSibling
    ItemNextSibling[This] = NextSibling
    ItemFirstChild [This] = FirstChild
    ItemLastChild  [This] = LastChild
    ItemParent     [This] = Parent

    This = Parent

    Type        = ItemType       [This]
    Class       = ItemClass      [This]
    Name        = ItemName       [This]
    Tag         = ItemTag        [This]
    Dims        = ItemDims       [This]
    Offset      = ItemOffset     [This]
    Size        = ItemSize       [This]
    Count       = ItemCount      [This]
    BitStart    = ItemBitStart   [This]
    BitEnd      = ItemBitEnd     [This]

    PrevSibling = ItemPrevSibling[This]
    NextSibling = ItemNextSibling[This]
    FirstChild  = ItemFirstChild [This]
    LastChild   = ItemLastChild  [This]
    Parent      = ItemParent     [This]
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# UpdateClose()
#
# Update CurrLoc from Size and Count and Close().
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function UpdateClose()
{
    if ((Size != -1) && (Count != -1))
    {
        CurrLoc = Offset + (Size * Count)
    }
    Close()
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# CloseDword()
#
# Put out ending string for previous register.
#
# Invoked when this line ends a register definition.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function CloseDword()
{
    if (OutputFormat == "mio")
    {
        # Output collected lines.
        CollectOut()

        if (End0String[Type] != "")
        {
            printf Nesting End0String[Type]
        }
        if (End1String[Type] != "")
        {
            printf Nesting End1String[Type], Dims
        }
        if (End2String[Type] != "")
        {
            printf Nesting End2String[Type], Name, Dims
        }
    }
    UpdateClose()
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# PrintOffsetChecks(name)
#
# Put out _RGD_Check_Offset stuff at the end of a blocks or module.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function PrintOffsetChecks(Name)
{
    # In conjunction with the macros defined at the tail end of the
    # BEGIN section, we put out code that, if compiled with
    #
    #   #define RGD_CHECK_OFFSETS 1
    #
    # will validate the offsets of the structure members against the
    # values we think they should be.
    #
    # We can't generate a compile time error because offsetof() and
    # sizeof() are not known at preprocessor time.  But we can generate
    # link errors; we need not wait until it runs.
    #
    # If there's an error, the macros generate a reference to the
    # unresolved symbol <struct>_<member>_offset_not_<offset> where
    # <struct> is the <module struct name> on the "module" line or the
    # name on the "blocks" line, <member> is the name of the member of
    # that structure, and <offset> is what we thought the offset should
    # have been.  You can tell where the failures are from the name.  If
    # you look at the .COD file generated by the compiler, the
    # unresolved function is invoked with the offset the compiler
    # actually found as the unsigned long parameter.
    #
    # For P9730, two new modules have been added to
    # Platform/CEPC/Kernel/Hal.  The module checkc.c validates the
    # offsets in C code, and checkcpp.cpp validates them in CPP code.
    #
    # Note that this whole house of cards depends on the compiler
    # optimizing away references like those inside the if:
    #
    #   if (0)
    #   {
    #       extern void foo(unsigned long);
    #       foo(123);
    #   }
    #
    # If isome later version of the compiler should no longer optimize
    # away the inner code, you'll get the unresolved references all the
    # time.

    Header = sprintf(                                                         \
        "\n"                                                                  \
        "#if        defined(RGD_CHECK_OFFSETS)\n"                             \
        "#if        RGD_CHECK_OFFSETS\n"                                      \
        "\n"                                                                  \
        "#define _RGD_offsetof(p, f) ((unsigned long) (&(((p))->f)))\n"       \
        "#define _RGD_Check_Offset(s, f, o)                              \\\n"\
        "    {                                                           \\\n"\
        "        extern void _##s##_##f##_offset_not_##o(                \\\n"\
        "            tp##s,                                              \\\n"\
        "            unsigned long                                       \\\n"\
        "        );                                                      \\\n"\
        "        (void) (                                                \\\n"\
        "            (_RGD_offsetof(pRegs, f) == 0x##o)                  \\\n"\
        "            ? 0                                                 \\\n"\
        "            : (                                                 \\\n"\
        "                _##s##_##f##_offset_not_##o(                    \\\n"\
        "                    pRegs,                                      \\\n"\
        "                    _RGD_offsetof(pRegs, f)                     \\\n"\
        "                ),                                              \\\n"\
        "                0                                               \\\n"\
        "            )                                                   \\\n"\
        "        );                                                      \\\n"\
        "    }                                                           \\\n"\
        "\n"                                                                  \
        "#pragma optimize(\"agpsw\", on)\n"                                   \
        "\n"                                                                  \
        "#if        defined(__cplusplus)\n"                                   \
        "extern \"C\" {\n"                                                    \
        "void _RGD_CPP_Check_%s_Offsets(p%s_t pRegs)\n"                       \
        "#else   // defined(__cplusplus)\n"                                   \
        "void _RGD_C_Check_%s_Offsets(p%s_t pRegs)\n"                         \
        "#endif  // defined(__cplusplus)\n"                                   \
        "{\n",
        Name,
        Name,
        Name,
        Name                                                                  \
    )

    for (i = FirstChild; i; i = ItemNextSibling[i])
    {
        # put out the offset checking code

        if (ItemType[i] == "block")
        {
            # go one level deeper if "block"
            for (j = ItemFirstChild[i]; j; j = ItemNextSibling[j])
            {
                if (ItemName[j] != "")
                {
                    printf Header
                    Header = ""
                    printf                                                    \
                        "    _RGD_Check_Offset(%s, %-30s %08x);\n",
                        Name,
                        ItemName[j] ",",
                        ItemOffset[j]
                }
            }
        }
        else {
            if (ItemName[i] != "")
            {
                printf Header
                Header = ""
                printf                                                        \
                    "    _RGD_Check_Offset(%s, %-30s %08x);\n",
                    Name,
                    ItemName[i] ",",
                    ItemOffset[i]
            }
        }
    }
    If (Header == "")
    {
        printf "}\n"
        printf "#pragma optimize(\"\", on)\n"
        printf "\n"
        printf "#if        defined(__cplusplus)\n"
        printf "}\n"
        printf "#endif  // defined(__cplusplus)\n"
        printf "\n"
        printf "#undef  _RGD_offsetof\n"
        printf "#undef  _RGD_Check_Offset\n"
        printf "\n"
        printf "#endif  // RGD_CHECK_OFFSETS\n"
        printf "#endif  // defined(RGD_CHECK_OFFSETS)\n"
        printf "\n"
    }
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# CloseBlocks()
#
# Put out ending stuff for previous "blocks".
#
# Invoked when this line ends a blocks definition.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function CloseBlocks(i, j, Header, Trailer)# local i, j, Header, Trailer
{
    Nesting = substr(Nesting, 5)
    if (OutputFormat == "mio")
    {
        printf Nesting "} %s_t, *p%s_t;\n", Name, Name

        PrintOffsetChecks(Name);
    }

    UpdateClose()
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# CloseModule()
#
# Put out ending stuff for previous "module".
#
# Invoked when this line ends a module definition.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #


function CloseModule(i, j, Header, Trailer)     # local i, j, Header, Trailer
{
    Nesting = substr(Nesting, 5)
    if (OutputFormat == "mio")
    {
        printf Nesting "} %s_NONVOLATILE_t;\n", StructNameFromModule[Name]
        printf                                                                \
            Nesting "typedef volatile %s_NONVOLATILE_t *p%s_t;\n",
            StructNameFromModule[Name],
            StructNameFromModule[Name]

        PrintOffsetChecks(StructNameFromModule[Name]);
    }

    UpdateClose()
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# next = ParseDimensions(
#     Word,             array containing words to parse
#     i,                start parsing at Word[i]
#     n                 parse Word[i] through Word[i + n - 1]
# )
#
# Parse dimensions.  May be none, of course.
#
# Returns index in Word array of next word to parse after dimensions.
#
# Globals set:
#    nDims      number of dimensions found; may be zero
#    Dim[j]     number of elements in jth dimension, 0 <= j < nDims
#    Dims       canonical string "[i][j][k]..."
#    Count      i * j * k * ...
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function ParseDimensions(Word, i, n, j)# local j
{
    # assume no dimensions
    nDims = 0
    Dims = ""

    # if there are any, accumulate each
    for (j = i; (j < (j + n)) && (Word[j] == "["); j += 3)
    {
        # syntax error?
        if (Word[j + 2] != "]")
        {
            printf                                                            \
                "!!line %d looking for %s] found %s\n",
                NR,
                Word[j] Word[j + 1],
                Word[j] Word[j + 1] Word[j + 2]
            next
        }
        Dim[nDims] = Decimal(Word[j + 1])
        Dims = Dims "[" Dim[nDims] "]"
        Count *= Dim[nDims]
        nDims++
    }
    if (j != (i + n))
    {
        printf "!!line %d dimension syntax: got %s from", NR, Dims
        for (j = i; j < (i + n); j++)
        {
            printf " %s", Word[j]
        }
        printf "\n"
        next
    }
    return(j)
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# CatchUp(Offset)
#
# Insert a filler char or char array to catch CurrLoc up to Offset.
#
# Note an error if Offset < CurrLoc.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function CatchUp(Offset)
{
    # compute distance to this register and insert filler if needed
    if (Offset < CurrLoc)
    {
        printf                                                                \
            "!!line %d %s at %05x out of order\n",
            NR,
            Name,
            Offset
    }
    else if (Offset != CurrLoc)
    {
        if (OutputFormat == "mio")
        {
            if (Offset == (CurrLoc - 1))
            {
                printf                                                        \
                    Nesting Volatile "unsigned char filler%05x;\n", CurrLoc
            }
            else {



                if (Offset - CurrLoc >= 2147483648.0)
                {
                    Offset = Offset - 2147483644.0
                    printf                                                    \
                        Nesting                                               \
                        Volatile "unsigned char filler%08x[0x%08x-0x%08x];\n",
                        CurrLoc,
                        Offset,
                        CurrLoc
                    CurrLoc = Offset
                    Offset += 2147483644.0
                    printf                                                    \
                        Nesting                                               \
                        Volatile "unsigned char filler%08x[0x%08x-0x%08x];\n",
                        CurrLoc,
                        Offset,
                        CurrLoc
                }
                else
                {
                    printf                                                    \
                        Nesting                                               \
                        Volatile "unsigned char filler%05x[0x%05x-0x%05x];\n",
                        CurrLoc,
                        Offset,
                        CurrLoc
                }
            }
        }
        CurrLoc = Offset
    }
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# processHierarchy(item, repeatTag)
#
# Put out stuff for URD format file.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function processHierarchy(                                                    \
    itemIndex,
    repeatOffset,
    repeatPrefix,
    fullPrefix,
    Byte,               # locals from here down
    hierarchy,
    i,
    iCount,
    iTab,
    Mask,
    maxCount,
    mmioOffset,
    myFullPrefix,
    myRepeatPrefix,
    Name,
    tempStr                                                                   \
)
{
# globals:
#   containerName
#   containerOffset
#   itemHierarchy
#   regExpr

# params=dll,module0,04f000,module1,005000
# stop repeating at 64
# put out offset in name if not unique

    itemHierarchy++
    for (; itemIndex; itemIndex = ItemNextSibling[itemIndex])
    {
        maxCount = ItemCount[itemIndex]
        if (maxCount <= 0)
        {
            maxCount = 1
        }
        if (maxCount > 64)      # no more than 64 repeats
        {
            maxCount = 64
        }

        # skip fillers, typedefs and previous typedefs
        if (                                                                  \
            (ItemName[itemIndex] !~ /^filler/) &&
            (ItemType[itemIndex] != "typedef")                                \
        )
        for (iCount = 0; iCount < maxCount; iCount++)
        {
            hierarchy = sprintf("%d:", itemHierarchy)
            tempStr = ""
            for (iTab = 1; iTab < itemHierarchy; iTab++)
            {
                tempStr = tempStr "  "
            }

            Name = ItemName[itemIndex]

            if (ItemClass[itemIndex] == ClassBlocks)
            {
                printf(hierarchy tempStr "\"%s\";\n", Name)
            }
            else
            if (                                                              \
                (ItemClass[itemIndex] == ClassBlock) ||
                (ItemClass[itemIndex] == ClassModule)                         \
            )                                                                 \
            {
                containerName = tolower(ItemName[itemIndex])
                containerOffset = ItemOffset[itemIndex]
                regExpr = "^" containerName "_"

                myRepeatPrefix = ""
                myFullPrefix = ""

                # URD tool can not deal with a block without any children
                if (ItemFirstChild[itemIndex] != 0)
                {
                    if (NameSeen[Name] == "")
                    {
                        printf(hierarchy tempStr "\"%s\";\n", Name)
                        NameSeen[Name]++
                    }
                    else
                    {
                        while (NameSeen[Name "_" NameSeen[Name]] != "")
                        {
                            NameSeen[Name]++
                        }
                        printf                                                \
                            hierarchy tempStr "\"%s\";\n",                    \
                            Name "_" NameSeen[Name]
                        NameSeen[Name "_" NameSeen[Name]]++
                    }
                }
            }
            else
            {
                mmioOffset =                                                  \
                    repeatOffset                                              \
                    + (iCount * ItemSize[itemIndex])                          \
                    + ItemOffset[itemIndex]

                # Make the name pretty.  Very ad hoc.
                #
                # First, we try just the bare ItemName
                #   srcBase
                # or, if there's a repeat,
                #   srcBase_2
                #
                # If that name's been put out already, we try ItemName
                # with the module or block prepended:
                #   de_srcBase
                #
                # If that's been used already, we try ItemName with the
                # block or module and repeat counts prepended:
                #   aicp_2_muxOrder
                #
                # If that's been used already, we use the block or
                # module, offset and repeat counts prepended:
                #   aicp00330_2_muxOrder

                # If block/module already prepended, remove it.
                if (Name ~ regExpr)
                {
                    Name = substr(Name, length(containerName) + 2)
                }


                # If a repeated item add iCount
                if ((maxCount > 1) && iCount)
                {
                    Name = Name "_" iCount
                    myRepeatPrefix = repeatPrefix iCount "_"
                }
                else
                {
                    myRepeatPrefix = repeatPrefix
                }
                myFullPrefix = fullPrefix Name "_"

                if (NameSeen[Name] != "")
                {
                    # We can't use just the bare name
                    if (NameSeen[containerName "_" Name] == "")
                    {
                        # We can use name with block/module prepended
                        Name = containerName "_" Name
                    }
                    else
                    {
                        if (NameSeen[containerName "_" repeatPrefix Name] == "")
                        {
                            # We can use name with repeat prefix
                            Name = containerName "_" repeatPrefix Name
                        }
                        else
                        {
                            # We have to use name with offsets
                            Name =                                            \
                                containerName                                 \
                                sprintf("%03x", mmioOffset)                   \
                                "_"                                           \
                                repeatPrefix Name
                        }
                    }
                }
                NameSeen[Name]++

                # Make sure Name is not longer then 30 chars...
                # The URD can't handle longer names...
                if (length (Name) > 30)
                {
                    Name = substr (Name, 0, 29);
                }

                if (ItemClass[itemIndex] == ClassStruct)
                {
                    # For a struct or union, we put out
                    #   <depth>:      "<block>_<name>";
                    #
                    # This shows up as a folder-like thingie in urd.

                    printf(hierarchy tempStr "\"%s\";\n", Name)
                }
                else

                # we put out
                #   <prettyname> [<offset>] & <mask>;

                if (ItemClass[itemIndex] == ClassField)
                {
                    if (ItemType[itemIndex] == "field")
                    {
                        Mask = 0
                        for (                                                 \
                            i = ItemBitStart[itemIndex];                      \
                            i <= ItemBitEnd[itemIndex];                       \
                            i++                                               \
                        )
                        {
                            Mask += 2^i
                        }
                        Mask = sprintf("%08x;", Mask)
                        # URD expects no hierarchy level on bottom level
                        # fields
                        hierarchy = "  "
                    }
                    else if (ItemType[itemIndex] == "byte")
                    {
                        Mask = ByteMaskValue[                                 \
                            ItemOffset[itemIndex]                             \
                            - ItemOffset[ItemParent[itemIndex]]               \
                        ] ";"
                        # URD expects no hierarchy level on bottom level
                        # fields
                        hierarchy = "  "
                    }
                    else
                    {
                        Mask = "ffffffff = 0x00000000;"
                    }

                    printf(                                                   \
                        "%-40s [0x%08x] & 0x%s\n",
                        hierarchy tempStr Name,
                        mmioOffset,
                        Mask                                                  \
                    )
                }
                else
                if (ItemClass[itemIndex] == ClassBits)
                {
                    printf(                                                   \
                        "%-40s [0x%08x] & 0xffffffff = 0x00000000;\n",
                        hierarchy tempStr Name,
                        mmioOffset                                            \
                    )
                }
            }
            if (ItemFirstChild[itemIndex])
            {
                processHierarchy(                                             \
                    ItemFirstChild[itemIndex],
                    repeatOffset + iCount * ItemSize[itemIndex],
                    myRepeatPrefix,
                    myFullPrefix                                              \
                )
            }
        }
    }
    itemHierarchy--
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# BEGIN
#
# Done before processing any part of input file.
#
# Initialize.  Define begin and end strings for register keywords.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

BEGIN {
    # table to look up digit integer from digit string
    HexDigitValue["0"] = 0
    HexDigitValue["1"] = 1
    HexDigitValue["2"] = 2
    HexDigitValue["3"] = 3
    HexDigitValue["4"] = 4
    HexDigitValue["5"] = 5
    HexDigitValue["6"] = 6
    HexDigitValue["7"] = 7
    HexDigitValue["8"] = 8
    HexDigitValue["9"] = 9
    HexDigitValue["A"] = 10
    HexDigitValue["B"] = 11
    HexDigitValue["C"] = 12
    HexDigitValue["D"] = 13
    HexDigitValue["E"] = 14
    HexDigitValue["F"] = 15
    HexDigitValue["a"] = 10
    HexDigitValue["b"] = 11
    HexDigitValue["c"] = 12
    HexDigitValue["d"] = 13
    HexDigitValue["e"] = 14
    HexDigitValue["f"] = 15

    # Masks for bytes in dword
    if (BigEndian)
    {
        ByteMaskValue[0] = "ff000000"
        ByteMaskValue[1] = "00ff0000"
        ByteMaskValue[2] = "0000ff00"
        ByteMaskValue[3] = "000000ff"
    }
    else
    {
        ByteMaskValue[0] = "000000ff"
        ByteMaskValue[1] = "0000ff00"
        ByteMaskValue[2] = "00ff0000"
        ByteMaskValue[3] = "ff000000"
    }

    # "bits" begins a bitfield dword register
    IsRegisterBegin["bits"] = 1
    Begin0String   ["bits"] = Volatile "union _%s\n"
    Begin1String   ["bits"] = "{\n"
    Begin2String   ["bits"] = "    " Volatile "struct\n"
    Begin3String   ["bits"] = "    {\n"
    BodyString     ["bits"] = ""
    End0String     ["bits"] = "    } bits;\n"
    End1String     ["bits"] = "    volatile unsigned long u32;\n"
    End2String     ["bits"] = "} %s%s;\n"

    # "bytes" begins a dword with 4 bytes
    IsRegisterBegin["bytes"] = 1
    Begin0String   ["bytes"] = Volatile "union _%s\n"
    Begin1String   ["bytes"] = "{\n"
    Begin2String   ["bytes"] = "    " Volatile "struct\n"
    Begin3String   ["bytes"] = "    {\n"
    BodyString     ["bytes"] = ""
    End0String     ["bytes"] = "    } bytes;\n"
    End1String     ["bytes"] = "    volatile unsigned long u32;\n"
    End2String     ["bytes"] = "} %s%s;\n"

    # CurrLoc is the current location counter.  It holds the offset of
    # the byte just after the last item defined.
    CurrLoc = 0

    # There are properties for each item we find:

    #   Type          "bits", "bytes", "struct", "union", "COLOR32", ...
    #   Class         nestability class:

    ClassOther  = 0             # world
    ClassBlocks = 1             # blocks
    ClassBlock  = 2             # block
    ClassModule = 3             # module
    ClassStruct = 4             # struct, union
    ClassBits   = 5             # typedef, bits, bytes, ...
    ClassField  = 6             # field, byte, ...

    ClassName[ClassOther]  = "Other"      # world
    ClassName[ClassBlocks] = "Blocks"     # blocks
    ClassName[ClassBlock]  = "Block"      # block
    ClassName[ClassModule] = "Module"     # module
    ClassName[ClassStruct] = "Struct"     # struct, union
    ClassName[ClassBits]   = "Bits"       # typedef, bits, bytes, ...
    ClassName[ClassField]  = "Field"      # field, byte, ...

    #   Name          name of item; null if unnamed struct or union
    #   Tag           tag of struct or union item; may be null
    #   Dims          dimensions of item; may be null
    #   Offset        offset in 9730 space of beginning of item
    #   Size          number of bytes in single item
    #   Count         number of items if array
    #   BitStart      offset to rightmost bit of item, if field
    #   BitEnd        number of bits in item, if field
    #   PrevSibling   item index of prev item at same nesting level
    #   NextSibling   item index of next item at same nesting level
    #   FirstChild    item index of first child if this item is a parent
    #   LastChild     item index of last child if this item is a parent
    #   Parent        item index of parent if this is in struct or union

    # The globals refer to the current item.  We remember the properties
    # in the arrays ItemType[], ItemName[], ...

    # Open() starts a new item, the next child of This.
    #
    # Close() updates ItemXxxx[This] from Xxxx and bumps This.

    # This is the index of the currently open item.  NextAvail is the
    # index of the item that will get snaggled on the next Open().

    NextAvail = 1

    # Except for some initial placeholding items, the Items form a
    # nested heirarchy.

    # A newly created Item gets its initial Class, Size and Count from
    # its Type, which may be a placeholder or a previously created Item.
    # The array ItemFromType[] gives the Item of that Type so we can
    # get the Class, Size and Count.

    CreatePlaceholder("previous",ClassBits,    4,  1)
    CreatePlaceholder("typedef", ClassBits,    4,  1)
    CreatePlaceholder("blocks",  ClassBlocks, -1, -1)
    CreatePlaceholder("block",   ClassBlock,  -1, -1)
    CreatePlaceholder("module",  ClassModule, -1, -1)
    CreatePlaceholder("struct",  ClassStruct, -1,  1)
    CreatePlaceholder("union",   ClassStruct, -1,  1)
    CreatePlaceholder("bits",    ClassBits,    4,  1)
    CreatePlaceholder("bytes",   ClassBits,    4,  1)
    CreatePlaceholder("field",   ClassField,  -1, -1)
    CreatePlaceholder("byte",    ClassField,  -1, -1)

    # The item "world" is the otherwise empty parent of everything
    # except placeholders.  It starts up Open but not otherwise useful.

    This = CreatePlaceholder("world", ClassOther, -1, -1)

    Type        = ItemType       [This]
    Class       = ItemClass      [This]
    Name        = ItemName       [This]
    Tag         = ItemTag        [This]
    Dims        = ItemDims       [This]
    Offset      = ItemOffset     [This]
    Size        = ItemSize       [This]
    Count       = ItemCount      [This]
    BitStart    = ItemBitStart   [This]
    BitEnd      = ItemBitEnd     [This]

    PrevSibling = ItemPrevSibling[This]
    NextSibling = ItemNextSibling[This]
    FirstChild  = ItemFirstChild [This]
    LastChild   = ItemLastChild  [This]
    Parent      = ItemParent     [This]

    Volatile = "volatile "
    if (OutputFormat != "urd")
    {
        OutputFormat = "mio"
    }
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Strip off comments.  Split the line into Word[1], Word[2], ...
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

{
    # strip off any remaining line endings:
    sub(/\r\n$/,"");
    sub(/\n$/,"");
    sub(/\r$/,"");

    Line = $0

    # strip comments
    sub(/\/\/.*$/, "", Line)

    WLine = Line

    # separate punctuation
    gsub(/[^_[:alnum:] ]/, " & ", WLine)

    # break into words in Word[1], Word[2], ...
    nWords = split(WLine, Word)

    # skip if blank
    if (!nWords)
    {
        next
    }
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# file <filename>
#
# Used to generate
#
#   #if        !defined(_<filename>_SEEN)
#   #define _<filename>_SEEN
#   .
#   .
#   .
#   #endif  // !defined(_<filename>_SEEN)
#
# surrounding the file.  We substitute "_" for "." in <filename>, and
# make it all upper case, so, for example, 9730.mio becomes
# _9730_MIO_SEEN.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

(Word[1] == "file") {

    if (FileName != "")
    {
        if (OutputFormat == "mio")
        {
            # if we're doing mio, allow multiple file declarations
            printf "#endif  // !defined(_%s_SEEN)\n", FileName
            FileName = ""
        }
        else if ((OutputFormat == "urd") && (Urd == ""))
        {
            print "#EndRegisterList"
        }
    }

    FileName = Word[2] Word[3] Word[4] Word[5] Word[6]

    if (OutputFormat == "mio")
    {
        FileName = toupper(FileName)
        gsub(/\./, "_", FileName)
        printf "#if        !defined(_%s_SEEN)\n", FileName
        printf "#define             _%s_SEEN\n", FileName
    }
    else if ((OutputFormat == "urd") && (Urd == ""))
    {
        FileStripPos = index(FileName, ".")
        if (FileStripPos >= 1)
            FileName = substr(FileName, 1, FileStripPos-1)
        printf "#BeginRegisterList \""
        print  FileName "urd.dll\""
        print  "0: " FileName " A4 D4;"
    }

    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# typedef    <some typedef stuff>  <name> ; // simple typedef
# exttypedef <some typedef stuff>  <name> ; // external simple typedef
#
# typedef {struct, union} {              // complex typedef
#     ... whatever ...
# } <name> [<dimensions>] ;
#
# Typedefs are assumed to refer to a single possibly dimensioned dword.
# We remember its name for use in later register declarations.
#
# We pass through simple typedefs. External simple typedefs are not
# passed through (they are expected to be defined earlier in an include
# file). We modify complex ones, emitting:
#
#   typedef union {
#       {struct, union} {
#           ... whatever ...
#       };
#       U32 dw;
#   } <name> [<dimensions>] ;
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

(                                                                             \
    (Word[1] == "previous") ||                                                \
    (Word[1] == "typedef") ||                                                 \
    (Word[1] == "exttypedef")                                                 \
)                                                                             \
{

    if (Word[1] == "exttypedef")
        Open("typedef")
    else
        Open(Word[1])

    if (Word[nWords] == ";")
    {
        # it's a simple previous or typedef
        # find <dimensions> if any
        for (i = 1; (Word[i] != "[") && (Word[i] != ";"); i++)
        {
        }
        ParseDimensions(Word, i, nWords - i)

        Name = Word[i - 1]

        IsRegisterBegin[Name] = 1
        Begin0String   [Name] = ""
        Begin1String   [Name] = ""
        Begin2String   [Name] = ""
        Begin3String   [Name] = ""
        BodyString     [Name] = Volatile Name " %s%s;\n"
        End0String     [Name] = ""
        End1String     [Name] = ""
        End2String     [Name] = ""

        ItemFromType   [Name] = This

        if (OutputFormat == "mio")
        {
            if (Type == "typedef" && Word[1] != "exttypedef")
            {
                print $0
            }
        }

        Close()
        next
    }
    if (Word[nWords] != "{")
    {
        printf "!!line %d %s %s %s %s ", NR, Word[1], Word[2], Word[3], Word[4]
        printf "syntax error for typedef\n"
    }

    if (OutputFormat == "mio")
    {
        print Nesting "typedef union"
        print Nesting "{"
        t = $0
        sub(/^[[:space:]]*typedef[[:space:]]*/, "", t)
        Nesting = Nesting "    "
        print Nesting Volatile t
    }

    NestingDepth = 1

    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Process lines contained in a typedef.
#
# We count the level of nested "{" and "}", dropping out of the typedef
# when we hit the trailing "}".
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

(Type == "typedef") {
    for (i = 1; i <= nWords; i++)
    {
        if (Word[i] == "{")
        {
            NestingDepth++
        }
        if (Word[i] == "}")
        {
            NestingDepth--
        }
        if (!NestingDepth)
        {
            break
        }
    }
    if (NestingDepth)
    {
        # still inside the typedef
        if (OutputFormat == "mio")
        {
            Collect = Nesting Volatile
            for (i = 1; i <= nWords; i++)
                Collect = Collect " " Word[i]
            Collect = Collect "\n"
            CollectAppend(Collect, 0)
        }
        next
    }

    if (OutputFormat == "mio")
    {
        CollectOut()

        # We've dropped out of the typedef in this line.
        # We need to put out Word[1] through Word[i - 1] first.
        if (i != 1)
        {
            printf substr(Nesting, 2) Volatile
            for (j = 1; j < i; j++)
            {
                printf " " Word[j]
            }
            printf "\n"
            for (j = i; j < nWords; j++)
            {
                Word[j - i + 1] = Word[j]
            }
            nWords -= i - 1
        }
        printf Nesting "} bits;\n"
        printf Nesting Volatile "unsigned long u32;\n"
    }

    Nesting = substr(Nesting, 5)
    Name = Word[2]
    Size = 4

    ParseDimensions(Word, 3, nWords - 3)

    IsRegisterBegin[Name] = 1
    Begin0String   [Name] = ""
    Begin1String   [Name] = ""
    Begin2String   [Name] = ""
    Begin3String   [Name] = ""
    BodyString     [Name] = Volatile Name " %s%s;\n"
    End0String     [Name] = ""
    End1String     [Name] = ""
    End2String     [Name] = ""

    ItemFromType   [Name] = This

    Close()

    if (OutputFormat == "mio")
    {
        printf Nesting
        for (i = 1; i <= nWords; i++)
        {
            if (i != 1)
            {
                printf " "
            }
            printf Word[i]
        }
        printf "\n"
    }
    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# blocks  <blocks name>
#
# Begin the struct that contains a set of blocks.
#
# Each set of blocks is bracketed:
#
#   typedef struct _<blocks name>
#   {
#       ... blocks
#   };
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Word[1] == "blocks" {

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    # close any open dwords
    if (Class == ClassBits)
    {
        CloseDword()
    }
    # error if any struct or union open
    if (Class == ClassStruct)
    {
        printf                                                                \
            "!!line %d blocks in struct/union %s\n",
            NR,
            $0
        next
    }

    # module is a separate hierarchy from blocks/block so we close
    # block and blocks if we're starting a module, and close module if
    # we're starting a block/blocks.

    # close any open block
    if (Class == ClassBlock)
    {
        UpdateClose()
    }
    # close any open blocks
    if (Class == ClassBlocks)
    {
        CloseBlocks()
    }

    # close any open module
    if (Class == ClassModule)
    {
        CloseModule()
    }

    # Reset current location counter
    CurrLoc = 0

    Open("blocks")

    Name = Word[2]

    if (OutputFormat == "mio")
    {
        printf Nesting "typedef volatile struct _%s\n", Name
        printf Nesting "{\n"
        Nesting = Nesting "    "
    }

    lcBlockName = ""            # no prefix outside blocks
    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# block  <block name>  <start address>..<end address>
#
# The 9730 memory mapped address space is divided into blocks:
#   00000..07fff   32  1K blocks
#   08000..0bfff    4  4K blocks
#   0c000..0ffff    1 16K block
#   10000..1ffff    1 64K block
#   20000..3ffff  128  1K blocks
#
# This division is blocks is only checked when the BlockChecking variable
# is set to "1".
#
# For each block we #define 2 symbols:
#   blk<block name>       starting 1K block number
#   blkSize<block name>   number of 1K chunks in block
#
# For each 1k subblock in the block we #define an additional symbol:
#   P9730blk<hex block number>  <block name>
# so we can build tables and so on.
#
# If C or C++ had the construct, these would be naturally implemented
# like sets in Pascal.  Too bad.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Word[1] == "block" {

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    # close any open dwords
    if (Class == ClassBits)
    {
        CloseDword()
    }
    # error if any struct or union open
    if (Class == ClassStruct)
    {
        printf                                                                \
            "!!line %d block in struct/union %s\n",
            NR,
            $0
        next
    }
    # close any open block
    if (Class == ClassBlock)
    {
        CatchUp(Offset + Size)
        UpdateClose()
    }

    Open("block")

    Name = Word[2]
    lcBlockName = tolower(Name)
    Offset = Hex(Word[3])
    Size = Hex(Word[6]) - Offset + 1

    if ((Word[4] != ".") || (Word[5] != "."))
    {
        printf "!!line %d ", NR
        printf "block %s %s ", Word[2], Word[3] Word[4] Word[5] Word[6]
        printf "'%s' should be '..'\n", Word[4] Word[5]
    }

    if (BlockChecking == 1)
    {
        # figure out the block size for the region
        if (                                                                  \
            ((Offset >= Hex("00000")) && (Offset <= Hex("07fff"))) ||         \
            ((Offset >= Hex("20000")) && (Offset <= Hex("3ffff")))            \
        )                                                                     \
        {
            BlockSize = 1024
        }
        else if ((Offset >= Hex("08000")) && (Offset <= Hex("0bfff")))
        {
            BlockSize = 4096
        }
        else if ((Offset >= Hex("0c000")) && (Offset <= Hex("0ffff")))
        {
            BlockSize = 16384
        }
        else if ((Offset >= Hex("10000")) && (Offset <= Hex("1ffff")))
        {
            BlockSize = 65536
        }
        else {
            printf                                                            \
                "!!line %d block %05x..%05x %s bad block size for region\n",
                NR,
                Offset,
                Offset + Size - 1,
                Name
        }
        if (Offset % BlockSize)
        {
            printf                                                            \
                "!!line %d block %05x..%05x %s start not on boundary\n",
                NR,
                Offset,
                Offset + Size - 1,
                Name
        }
        if (Size != BlockSize)
        {
            printf                                                            \
                "!!line %d block %05x..%05x %s end block not in start block\n",
                NR,
                Offset,
                Offset + Size - 1,
                Name
        }
    }

    CatchUp(Offset)

    BlockDefines = BlockDefines                                               \
        sprintf(                                                              \
            "#define blk%-32s 0x%02x\n",
            Name,
            Offset / 1024                                                     \
        )

    BlockSizeDefines = BlockSizeDefines                                       \
        sprintf(                                                              \
            "#define blkSize%-32s %3d\n",
            Name,
            Size / 1024                                                       \
        )

    for (i = Offset / 1024; i < (Offset + Size) / 1024; i++)
    {
        BlockNameFromBlock[i] = Name
    }

    ItemFromBlockOrModule[Name] = This

    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# module  <module name> <module struct name> <module id>[,<module id>[, ...]]
#
# There are two different ways of using the rgd stuff.
#
# With the first, you use
#   blocks  <blocks name>
# and
#   block  <block name>  <start address>..<end address>
# to define a chip's aperture, with all its blocks.  The run time
# environment will use a pointer to the entire aperture, with each
# block's registers being reference by offsets in the aperture.
#
# With the second, each block or module is declared more or less
# independently with
#  module  <module name> <module typedef name> <module id>
# used to declare the module.  The run time environment will have a
# pointer to each of the modules, and references to the registers will
# be via offsets from the beginning of the block.
#
# This script is not intended to support use of blocks/block mixed with
# module.
#
# Example:
#
#   module De tmhwDrawDeRegs 0117
#
# brackets the register declarations with
#
#   typedef struct _tmhwDrawDeRegs {
#       ... registers ...
#   } tmhwDrawDeRegs;
#   typedef volatile tmhwDrawDeRegs *ptmhwDrawDeRegs;
#
# Bitfields, bytes, etc. that we generate inside the module will have
# <module name> as a prefix on the union or struct tag:
#
#   bits       vecConst               0043c // Bresenham vector terms
#     15:00      const0                     // 2*dmin - 2*dmax
#     31:16      const1                     // 2*dmin
#
# generates
#
#   union _deVecConst
#   {
#       struct
#       {
#           unsigned long const0 : 16;
#           unsigned long const1 : 16;
#       } bits;
#       unsigned long u32;
#   } vecConst;
#
# We also generate
#
#   #define _RGD_Module_Id_Of_De               0117
#   #define _RGD_Hex_Module_Id_Of_De           0x0117
#   #define _RGD_Module_Name_Of_0117           De
#
# for building integration tables.
#
# You can have a single module definition used for multiple physical
# modules.  For example, there are two AICP modules in the 3218.  So if
# you say
#
#   module AICP tmhwAicpRegs 0111,0118
#
# the struct generated is unchanged, but for integration you get
#
#   #define _RGD_n_Module_Ids_For_AICP           2
#   #define _RGD_Module_Id_0_Of_AICP             0111
#   #define _RGD_Hex_Module_Id_0_Of_AICP         0x0111
#   #define _RGD_Module_Name_Of_0111             AICP
#   #define _RGD_Module_Id_1_Of_AICP             0118
#   #define _RGD_Hex_Module_Id_1_Of_AICP         0x0118
#   #define _RGD_Module_Name_Of_0118             AICP
#
# When generating a .URD file, you get two structs.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Word[1] == "module" {

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    # close any open dwords
    if (Class == ClassBits)
    {
        CloseDword()
    }
    # error if any struct or union open
    if (Class == ClassStruct)
    {
        printf                                                                \
            "!!line %d module in struct/union %s\n",
            NR,
            $0
        next
    }

    # module is a separate hierarchy from blocks/block so we close
    # block and blocks if we're starting a module, and close module if
    # we're starting a block/blocks.

    # close any open block
    if (Class == ClassBlock)
    {
        UpdateClose()
    }
    # close any open blocks
    if (Class == ClassBlocks)
    {
        CloseBlocks()
    }

    # close any open module
    if (Class == ClassModule)
    {
        CloseModule()
    }

    # Reset current location counter
    CurrLoc = 0

    Open("module")

    # module <module name> <struct name> <module id>[,<module id>...]
    #
    # module AICP tmhwAicpRegs 0111,0118
    #
    # We remember
    #   module name   in Name, in the hierarchy
    #   struct name   in StructNameFromModule[Name]
    #   module name   in all the ModuleFromId[<module id>]
    #   module ids    in IdFromModule[Name "." <0 .. (# module ids - 1)>]
    Name = Word[2]
    StructNameFromModule[Name] = Word[3]
    i = -1
    do
    {
        i++

        # IdFromModule[Name "." m], with m in 0..n-1
        # 0..n-1 corresponds to Word[4], Word[6], ... Word[4 + (2 * n)]
        ModuleFromId[Word[(i * 2) + 4]] = Name
        IdFromModule[Name "." i] = Word[(i * 2) + 4]

    } while (Word[(i * 2) + 5] == ",")

    # remember the module name as prefix for generated unions
    lcBlockName = tolower(Word[2])

    if (OutputFormat == "mio")
    {
        if (i)                  # if more than one module Id
        {
            # for 
            #   module AICP tmhwAicpRegs 0111,0118
            # we put out
            #   #define _RGD_n_Module_Ids_For_AICP           2
            #   #define _RGD_Module_Id_0_Of_AICP             0111
            #   #define _RGD_Hex_Module_Id_0_Of_AICP         0x0111
            #   #define _RGD_Module_Name_Of_0111             AICP
            #   #define _RGD_Module_Id_1_Of_AICP             0118
            #   #define _RGD_Hex_Module_Id_1_Of_AICP         0x0118
            #   #define _RGD_Module_Name_Of_0118             AICP
            printf                                                            \
                Nesting "#define _RGD_n_Module_Ids_For_%-12s   %s\n",
                Name,
                i + 1
            for (i = 0; IdFromModule[Name "." i] != ""; i++)
            {
                printf                                                        \
                    Nesting "#define _RGD_Module_Id_%d_Of_%-14s   %s\n",
                    i,
                    Name,
                    Word[(i * 2) + 4]
                printf                                                        \
                    Nesting "#define _RGD_Hex_Module_Id_%d_Of_%-10s   0x%s\n",
                    i,
                    Name,
                    Word[(i * 2) + 4]
                printf                                                        \
                    Nesting "#define _RGD_Module_Name_Of_%-14s   %s\n",
                    IdFromModule[Name "." i],
                    Name
            }
        }
        else
        {
            # for 
            #   module De tmhwDeRegs 0117
            # we put out
            #   #define _RGD_Module_Id_Of_De               0117
            #   #define _RGD_Hex_Module_Id_Of_De           0x0117
            #   #define _RGD_Module_Name_Of_0117           De
            printf                                                            \
                Nesting "#define _RGD_Module_Id_Of_%-14s   %s\n",
                Word[2],
                Word[4]
            printf                                                            \
                Nesting "#define _RGD_Hex_Module_Id_Of_%-10s   0x%s\n",
                Word[2],
                Word[4]
            printf                                                            \
                Nesting "#define _RGD_Module_Name_Of_%-12s   %s\n",
                IdFromModule[Name "." 0],
                Name
        }
        printf Nesting "typedef struct _%s\n", Word[3]
        printf Nesting "{\n"
        Nesting = Nesting "    "
    }

    ItemFromBlockOrModule[Name] = This

    next
}




# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# struct [tag] { [offset]
# union [tag] { [offset]
#
# Begin a struct or union.  Useful for arrays of structs or for unions.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

(Word[1] == "struct") || (Word[1] == "union") {

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    # close any open dwords
    if (Class == ClassBits)
    {
        CloseDword()
    }
    Open(Word[1])

    if (Word[2] != "{")
    {
        # must be struct tag { [offset]
        if (Word[3] != "{")
        {
            printf                                                            \
                "!!line %d %s expected %s {\n",
                NR,
                Word[1] Word[2] Word[3] Word[4] Word[5] Word[6] Word[7],
                Word[1] Word[2]
            next
        }
        Tag = Word[2]
        if (Word[4] != "")
        {
            Offset = Hex(Word[4])
        }
        else {
            Offset = CurrLoc
        }
    }
    else {
        Tag = ""
        if (Word[3] != "")
        {
            Offset = Hex(Word[3])
        }
        else {
            Offset = CurrLoc
        }
    }
    CatchUp(Offset)

    if (OutputFormat == "mio")
    {
        printf Nesting Volatile "%s %s {\n", Type, Tag
        Nesting = Nesting "    "
    }

    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# } [<structure name>] [<dimensions>] ;
#
# End a structure or union.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

(Word[1] == "}") {

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    # close any open dwords
    if (Class == ClassBits)
    {
        CloseDword()
    }

    if (Word[nWords] != ";")
    {
        # add trailing ";"
        Word[++nWords] = ";"
    }
    if ((Word[2] != "[") && (Word[2] != ";"))
    {
        Name = Word[2]
        ParseDimensions(Word, 3, nWords - 3)
    }
    else {
        Name = ""
        ParseDimensions(Word, 2, nWords - 2)
    }
    if ((Tag != "") && (Name == ""))
    {
        # Let's say that inside some struct you have
        #
        #   struct Foo {
        #     ... stuff ...
        #   };
        #
        # In C, that struct declaration allocates space.  But in C++, it
        # declares a type without allocating space.
        #
        # Thus such a construct would be interpreted differently in C or
        # C++, messing up the purpose of the .rgd file.  So we make it
        # illegal.

        printf "!!line %d at %s: %s %s has no name\n", NR, Offset, Type, Tag
    }
    # A struct is the size of its contents.
    # A union is the size of its largest child.
    if (Type == "struct")
    {
        Size = CurrLoc - Offset
    }
    else {
        Size = 0
        if (i = FirstChild)
        {
            do
            {
                if (Size < (ItemSize[i] * ItemCount[i]))
                {
                    Size = ItemSize[i] * ItemCount[i]
                }
                i = ItemNextSibling[i]
            } while (i != LastChild)
	    
	    if (FirstChild != LastChild)
	    {
	        if (Size < (ItemSize[LastChild] * ItemCount[LastChild]))
                {
                    Size = ItemSize[LastChild] * ItemCount[LastChild]
                }
	    }
        }
    }

    if (OutputFormat == "mio")
    {
        Nesting = substr(Nesting, 5)
        printf Nesting "} %s ;\n", Name Dims
    }

    UpdateClose()

    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# bytes      Color[256]           00400 // memory mapped access to palette
# bits       VIPPortCtl           00800
# COLOR32    CompareColor         0141c // color to which we compare
#
# If this line's keyword is the beginning of a register definition,
# close out the previous definition and start this one.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

IsRegisterBegin[Word[1]] != 0 { # start new register definition

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    # close any open dwords
    if (Class == ClassBits)
    {
        CloseDword()
    }
    Open(Word[1])

    PrefixName = Name = Word[2]

    # If bits or bytes, we want to prefix the union name with the block
    # name so we don't get collisions.  Only do so if the block name is
    # not already there, though.

    if (                                                                      \
        (Type == "bits" || Type == "bytes") &&                                \
        (lcBlockName != "") &&                                                \
        (tolower(substr(Word[2], 1, length(lcBlockName))) != lcBlockName)     \
    )
    {
        PrefixName =                                                          \
            lcBlockName                                                       \
            toupper(substr(Word[2], 1, 1))                                    \
            substr(Word[2], 2);
    }

    Offset = Hex(Word[nWords])

    ParseDimensions(Word, 3, nWords - 3)

    # Type      "bits", "bytes", "COLOR32", ...
    # Name      name, from Word[2]
    # Offset    offset, from Word[nWords]
    # nDims     number of dimensions found; may be zero
    # Dim[j]    number of elements in jth dimension, 0 <= j < nDims
    # Dims      canonical string "[i][j][k]..."
    # Count     i * j * k * ...

    # check that it's dword aligned
    if (Offset % 4)
    {
        printf "!!line %d %s at %s ", NR, Name, Offset
        printf "not dword aligned\n"
    }

    # we can now use this in a later declaration
    IsRegisterBegin[Name] = 1
    Begin0String   [Name] = ""
    Begin1String   [Name] = ""
    Begin2String   [Name] = ""
    Begin3String   [Name] = ""
    BodyString     [Name] = Volatile "union _" PrefixName " %s%s;\n"
    End0String     [Name] = ""
    End1String     [Name] = ""
    End2String     [Name] = ""

    ItemFromType[Name] = This

    CatchUp(Offset)

    if (OutputFormat == "mio")
    {
        if (Begin0String[Type] != "")
        {
            printf Nesting Begin0String[Type], PrefixName
        }
        if (Begin1String[Type] != "")
        {
            printf Nesting Begin1String[Type]
        }
        if (Begin2String[Type] != "")
        {
            printf Nesting Begin2String[Type]
        }
        if (Begin3String[Type] != "")
        {
            printf Nesting Begin3String[Type]
        }
        if (BodyString[Type] != "")
        {
            printf Nesting BodyString[Type], Name, Dims
        }
    }

    CurrentBitLocation = 0
    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# [[<start bit position>]:]<end bit position> <name>
#
# Declare a bitfield in a dword bits register.
#
# Example:
#         u 07:00    Rop                 // 3 op, Windows' definition
# declares Rop as the unsigned bitfield in bits 7..0 of the dword
# register.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

(Type == "bits") && (                                                         \
    IsDecimal(Word[1]) ||                                                     \
    (Word[1] == ":") ||                                                       \
    (                                                                         \
        ((Word[1] == "s") || (Word[1] == "u")) &&                             \
        (IsDecimal(Word[2]) || (Word[2] == ":"))                              \
    )                                                                         \
) {

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    Open("field")

    Signage = "un"              # assume unsigned

    if ((Word[1] == "s") || (Word[1] == "u"))
    {
        if (Word[1] == "s")
        {
            Signage = ""        # it's signed
        }
        # toss the "s" or "u"
        for (i = 2; i <= nWords; i++)
        {
            Word[i - 1] = Word[i]
        }
        nWords--
    }
    if (Word[1] == ":")
    {
        # we've just got :nn Name; toss the :
        for (i = 2; i <= nWords; i++)
        {
            Word[i - 1] = Word[i]
        }
        nWords--
    }
    if (Word[2] == ":")
    {
        # we've got ss:ee Name
        BitStart = Decimal(Word[3])
        BitEnd = Decimal(Word[1])
        Name = Word[4]
    }
    else {
        # we've just got ss Name
        BitStart = Decimal(Word[1])
        BitEnd = BitStart
        Name = Word[2]
    }
    if (BitEnd < BitStart)
    {
        print Word[1], Word[2], Word[3], Word[4], Word[5]
        printf "!!line %d %s in %s at %05x ", NR, Name, ItemName[Parent], Offset
        printf " end < start (%d < %d)\n", BitEnd, BitStart
    }
    else if (BitStart < CurrentBitLocation)
    {
        printf "!!line %d %s in %s at %05x ", NR, Name, ItemName[Parent], Offset
        printf " out of order ( %d < %d)\n", BitStart, CurrentBitLocation
    }
    else if (BitEnd >= 32)
    {
        printf "!!line %d %s in %s at %05x ", NR, Name, ItemName[Parent], Offset
        printf " end of %d is too many bits\n", BitEnd
    }
    else if (BitStart != CurrentBitLocation)
    {
        # Collect output lines for bitfield to reverse order later
        # depending on endianess.
        #
        if (OutputFormat == "mio")
        {
            Collect = sprintf(                                                \
                        "%s        unsigned long : %d;\n",
                        Nesting,
                        BitStart - CurrentBitLocation)
            CollectAppend(Collect, 0)
        }
        CurrentBitLocation = BitStart
    }

    if (OutputFormat == "mio")
    {
        Collect = sprintf(                                                    \
                    "%s        " Volatile Signage "signed long %s : %d;\n",
                    Nesting,
                    Name,
                    BitEnd - BitStart + 1)
        CollectAppend(Collect, 0)
    }

    CurrentBitLocation = BitEnd + 1

    UpdateClose()
    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# <byte number> <name>
#
# Declare a byte in a dword bytes register.
#
# Example:
#           0      Blue               // blue component
# declares Blue as the byte in bits 7..0 of the dword register.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

(Type == "bytes") && IsDecimal(Word[1]) && (Word[1] <= 3) {

    # close any open fields
    if (Class == ClassField)
    {
        UpdateClose()
    }
    Open("byte")

    Byte = Word[1]
    Name = Word[2]

    Count = 1
    Size = 1

    ParseDimensions(Word, 3, nWords - 2)
    BytesCount = Count

    Offset = ItemOffset[Parent] + Byte

    CatchUp(Offset)

    # Collect output lines for BYTES keywords to reverse order later
    # depending on endianess.
    #

    if (OutputFormat == "mio")
    {
        Collect = sprintf(                                                    \
            "%s        " Volatile "unsigned char %s%s;\n",
            Nesting,
            Name,
            Dims                                                              \
        )
        CollectAppend(Collect, 0)
    }

    UpdateClose()
    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# val <name> <value>
#
# Declare a value for a field or byte in a dword register
#
# Example:
#    val      SRC_HMono              2 //   host byte packed mono bitmap
# declares SRC_HMono to be the value 2 in its field in the dword register
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Word[1] == "val" {
    ValName = Word[2]
    Value = Word[3]
    for (i = 4; i <= nWords; i++)
    {
        Value = Value " " Word[i]
    }

    # flag a problem if we're redefining a val
    if (ValSeen[ValName] && (Val[ValName] != Value))
    {
        printf                                                                \
            "!!val %s was `%s' redefined as `%s' at line %d in %s at %05x\n",
            ValName,
            Val[ValName],
            Value,
            NR,
            Name,
            Offset
    }
    Val[ValName] = Value
    ValSeen[Valname] = 1

    if (OutputFormat == "mio")
    {
        if (Class == ClassBits)
        {
            # Collect output lines for VAL keywords inside bitfields definitions
            NumCollect++
            CollectType[NumCollect] = 1;
            CollectOutput[NumCollect] = sprintf(                              \
                "#define %-32s %10s\n", ValName, Value)
        }
        else
        {
            printf "#define %-32s %10s\n", ValName, Value
        }
    }
    next
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Catch any undefined lines
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

{
    printf "!!line %d in %s at %05x ", NR, Name, Offset
    printf " unrecognized: %s\n", $0
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# END
#
# If any register definition is dangling, close it off.
#
# This is executed after all input files have been processed.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

END {
    # close any open dwords
    if (Class == ClassBits)
    {
        CloseDword()
    }
    # note any dangling struct/union
    while (Class == ClassStruct)
    {
        printf "!! struct/union %s not closed\n", Name
        UpdateClose()
    }

    # module is a separate hierarchy from blocks/block so we close
    # block and blocks if we're starting a module, and close module if
    # we're starting a block/blocks.

    # close any open block
    if (Class == ClassBlock)
    {
        CatchUp(Offset + Size)
        UpdateClose()
    }
    # close any open blocks
    if (Class == ClassBlocks)
    {
        CloseBlocks()
    }

    # close any open module
    if (Class == ClassModule)
    {
        CloseModule()
    }

    # dump the block #defines
    if (DumpBlocks == "1")
    {
        printf BlockDefines
        printf BlockSizeDefines
        for (i = 0; i < 256; i++)
        {
            if (BlockNameFromBlock[i] != "")
            {
                printf(                                                       \
                    "#define PBlk%02x    %s\n",
                    i,
                    BlockNameFromBlock[i]                                     \
                )
            }
        }
    }


    if (OutputFormat == "urd")
    {
        if (Urd == "")
        {
            # Put out the old-stype .URD file
            #
            # Lookup root of "blocks" hierarchy and process it for the
            # URD format.

            processHierarchy(ItemFirstChild[ItemFromType["world"]], "", "", "")
        }
        else
        {
            # Parse Urd and put out what's desired.
            #
            # Urd=<dllname>,<module name>=<offset>[,<module name>=<offset>...]
            nWords = split(Urd, Word, ",")
            printf "#BeginRegisterList \"%surd.dll\"\n", Word[1]
            printf "0:%s A4 D4;\n", Word[1]
            for (i = 2; i <= nWords; i++)
            {
                j = split(Word[i], UrdWord, "=")
                if ((j != 2) || (ItemFromBlockOrModule[UrdWord[1]] ==""))
                {
                    printf                                                    \
                        "!! Urd huh? %s, %d, <%s>, <%s>, %d\n",
                        Word[i],
                        j,
                        UrdWord[1],
                        UrdWord[2],
                        ItemFromBlockOrModule[UrdWord[1]]
                }
                else
                {
                    processHierarchy(                                         \
                        ItemFromBlockOrModule[UrdWord[1]],
                        Hex(UrdWord[2]),
                        "",
                        ""                                                    \
                    )
                }
            }
        }
    }

    if (DEBUG)
    {

        # dump the symbol tree for debugging

        print "/*"
        for (i = 1; i < NextAvail; i++)
        {
            if (i != 1) {
                print
            }
            printf                                                            \
                "   Item=%d Name=<%s> Tag=<%s> Type=<%s> Class=<%s>\n",
                i,
                ItemName[i],
                ItemTag[i],
                ItemType[i],
                ClassName[ItemClass[i]]
            printf                                                            \
                "       Dims=<%s> Offset=<%05x> Size=<%d> Count=<%d> "        \
                "BitStart=<%d> BitEnd=<%d>\n",
                ItemDims[i],
                ItemOffset[i],
                ItemSize[i],
                ItemCount[i],
                ItemBitStart[i],
                ItemBitEnd[i]
            printf                                                            \
                "       PrevSibling=<%s> NextSibling=<%s>\n",
                ItemName[ItemPrevSibling[i]],
                ItemName[ItemNextSibling[i]]
            printf                                                            \
                "       FirstChild=<%s> LastChild=<%s> Parent=<%s>\n",
                ItemName[ItemFirstChild[i]],
                ItemName[ItemLastChild[i]],
                ItemName[ItemParent[i]]
            if (ItemType[i] == "module")
            {
                printf                                                        \
                    "         struct=<%s> id=<%s>",
                    StructNameFromModule[ItemName[i]],
                    IdFromModule[ItemName[i] "." 0]
                for (j = 1; IdFromModule[ItemName[i] "." j] != ""; j++)
                {
                    printf ",<%s>", IdFromModule[ItemName[i] "." j]
                }
                printf "\n"
            }
        }
        print " */"
    }

    if (OutputFormat == "mio")
    {
        if (FileName != "")
        {
            printf "#endif  // !defined(_%s_SEEN)\n", FileName
        }
    }
    else if (OutputFormat == "urd")
    {
        print "#EndRegisterList"
    }
}
