• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
    • Interfacing-tools
    • Hardware-verification
      • Gl
      • Esim
      • Vl2014
        • Warnings
        • Primitives
        • Use-set
        • Syntax
        • Getting-started
        • Utilities
        • Loader
        • Transforms
        • Lint
        • Mlib
          • Scopestack
          • Filtering-by-name
          • Vl-namefactory
          • Substitution
          • Allexprs
          • Hid-tools
            • Following-hids
            • Vl-hidexpr-traverse-datatype
            • Abstract-hids
            • Vl-hidexpr-find-type
          • Vl-consteval
          • Range-tools
          • Lvalexprs
          • Hierarchy
          • Finding-by-name
          • Expr-tools
          • Expr-slicing
          • Stripping-functions
          • Stmt-tools
          • Modnamespace
          • Vl-parse-expr-from-str
          • Welltyped
          • Reordering-by-name
          • Flat-warnings
          • Genblob
          • Expr-building
          • Datatype-tools
          • Syscalls
          • Relocate
          • Expr-cleaning
          • Namemangle
          • Caremask
          • Port-tools
          • Lvalues
        • Server
        • Kit
        • Printer
        • Esim-vl
        • Well-formedness
      • Sv
      • Fgl
      • Vwsim
      • Vl
      • X86isa
      • Svl
      • Rtl
    • Software-verification
    • Math
    • Testing-utilities
  • Mlib

Hid-tools

Functions for recognizing and following well-formed hierarchical identifiers, scoped identifiers, and indexing expressions.

VL Terminology

SystemVerilog provides a very rich syntax for referring to objects in different scopes and throughout the module hierarchy. To deal with this rich syntax, we will need a bit of jargon. These terms are well-defined notions in VL, but may not necessarily be found or used in the same way in the Verilog/SystemVerilog standards.

Identifiers. We say the following expressions are just identifiers. Note that the Verilog/SystemVerilog standards sometimes distinguish between plain and escaped identifiers. While our lexer needs to understand these as different notions, internally there is no difference.

foo
\foo$bar

Note that any indexing/selection operations after an identifier is not part of the identifier. For instance, foo[3] and foo[3:0] are not identifiers: they are index/selection operations applied to the identifier foo. (This may seem obvious, but we draw your attention to it because it is less obvious for hierarchical identifiers.)

Hierarchical identifiers. Identifiers can be chained together, perhaps with indexing, to form hierarchical identifiers. Here are examples of hierarchical identifiers:

foo                     // any ID is a HID
\foo$bar

foo.bar                 // fancier HIDs
foo.bar.baz

foo.bar[3].baz          // Verilog-2005 or SystemVerilog-2012
foo.bar[3][4].baz       // SystemVerilog-2012

Hierarchical identifiers may have internal indexing expressions. However, any subsequent indexing/selection operations are not part of the HID itself. For instance, we say that foo.bar[3].baz[2] and foo.bar[3].baz[3:0] are not a hierarchical identifiers. Instead, these are indexing/selection operators applied to a HID.

Scope expressions. Hierarchical identifiers can be prefixed with scoping operations, e.g., for packages. Here are some examples of scope expressions:

foo                             // any ID is a scope expression
\foo$bar

foo.bar                         // any HID is a scope expression
foo.bar.baz
foo.bar[3].baz
foo.bar[3][4].baz

mypkg::foo                      // fancier scope expressions
mypkg::foo.bar
$unit::foo::bar.baz[3].beep

As with ordinary identifiers and hierarchical identifiers, scope expressions do not have any indexing/selection operators. For example, mypkg::foo[3] is not a scope expression, but is instead an indexing operator applied to the scope expression mypkg::foo.

Index expressions. Scope expressions can be indexed into by some number of individual bit/array-indexing operations. Here are some examples of index expressions:

foo                             // any ID is an index expression
\foo$bar

foo.bar                         // any HID is an index expression
foo.bar.baz
foo.bar[3].baz
foo.bar[3][4].baz

mypkg::foo                      // any scope expression is an index expression
mypkg::foo.bar
$unit::foo::bar.baz[3].beep

foo[3]                          // fancier index expressions
foo[3][4][5]
foo.bar[3]
mypkg::foo[3][4][5]
$unit::foo::bar.baz[3].beep[2][1][0]

Note that an index expression does not have any part/range selects in it. That is, an expression like foo[3][5:0] is not an index expression; instead it is a part-selection operator applied to the index expression foo[3].

Note that part/range selection operations, like foo[3:0], are just an ordinary operator and we do not give them any special designation. Why, then, do we give special treatment to indexing? In short, part-selection is simpler than indexing because there can be at most a single part-select. In contrast, there can be many levels of array indexing, and so typically indexing needs to be handled recursively.

Low Level Representation

VL internally represents hierarchical identifiers as compound vl-expr-p objects. To understand the structure, consider a very complex index expression such as:

ape::bat::cat.dog[3][2][1].elf[7][6][5]

We expect to represent this sort of expression by nesting operations as suggested by the parentheses below. This arrangement matches the jargon above.

Indexing is the outermost operation:

  (((  ape::bat::cat.dog[3][2][1].elf     )[7] )[6] )[5]
       ------------------------------   -------------------
                a scopexpr              recursive indexing


Followed by scoping:

             ape::(bat::         (cat.dog[3][2][1].elf)  )
       ---------------------      --------------------
         recursive scoping              a hidexpr


Followed by hierarchy:

                     cat . ((dog [3][2][1]) . elf)
                           -----------------------
                                sub hidexpr

With hierarchical indexing going from outermost to innermost:

                           ((dog [3])[2])[1]
                           -----------------
                              a hidindex

Where each . is represented by a :vl-hid-dot operator, each [] by a :vl-index operator, each :: by a :vl-scope operator, and the names are represented as vl-hidpiece-p atoms.

Abstract Representation

The low-level vl-expr-p representation is not very strongly typed and permits nonsensical expressions like foo.5.bar.(1+2), which should never be produced by our parser or by well-behaving internal VL code. Because of this, most functions for working with HIDs should not and do not use the internal representation directly.

Instead, in abstract-hids, we set up wrapper functions that provide an interface for working with hierarchical identifier expressions at a somewhat higher level. These wrapper functions include stronger recognizers that ensure that an expression is a well-formed hierarchical identifier, scope expression, or index expression that meets our usual expectations. It also provides convenient accessor functions for traversing well-formed expressions.

Following HIDs

For many kinds of transformation and analysis, the fundamental operation on hierarchical, scoped, or indexed expressions is to follow them to what they refer to. To do this correctly requires an detailed understanding of both the concepts above and also scopestacks for looking up identifiers.

Due to this complexity, most code throughout VL should never try to follow hierarchical identifiers on its own. Instead, most code should be make use of the high-level functions described in following-hids.

Subtopics

Following-hids
Functions for following hierarchical identifiers.
Vl-hidexpr-traverse-datatype
Given a dotted expression that indexes into a datatype, find the type of the expression.
Abstract-hids
Recognizers for certain kinds of HID expressions.
Vl-hidexpr-find-type
Looks up a HID in a scopestack and looks for a declaration, returning the type and dimensionlist if found.