• 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
          • Preprocessor
            • Vl-iframe-p
            • Preprocessor-ifdef-minutia
              • Vl-preprocess-loop
              • Vl-read-until-end-of-define
              • Vl-expand-define
              • Vl-read-include
              • Vl-process-ifdef
              • Vl-substitute-into-macro-text
              • Vl-preprocess
              • Vl-define
              • Vl-process-define
              • Vl-process-undef
              • Preprocessor-include-minutia
              • Vl-split-define-text
              • Vl-read-timescale
              • Vl-line-up-define-formals-and-actuals
              • Vl-process-else
              • Vl-process-endif
              • Vl-istack-p
              • Vl-is-compiler-directive-p
              • Vl-check-remaining-formals-all-have-defaults
              • Vl-safe-previous-n
              • Vl-safe-next-n
              • Vl-defines
              • *vl-preprocess-clock*
            • Vl-loadconfig
            • Lexer
            • Vl-loadstate
            • Parser
            • Vl-load-merge-descriptions
            • Scope-of-defines
            • Vl-load-file
            • Vl-flush-out-descriptions
            • Vl-description
            • Vl-loadresult
            • Vl-read-file
            • Vl-find-basename/extension
            • Vl-find-file
            • Vl-read-files
            • Extended-characters
            • Vl-load
            • Vl-load-main
            • Vl-load-description
            • Vl-descriptions-left-to-load
            • Inject-warnings
            • Vl-load-descriptions
            • Vl-load-files
            • Vl-load-summary
            • Vl-collect-modules-from-descriptions
            • Vl-descriptionlist
          • Transforms
          • Lint
          • Mlib
          • Server
          • Kit
          • Printer
          • Esim-vl
          • Well-formedness
        • Sv
        • Fgl
        • Vwsim
        • Vl
        • X86isa
        • Svl
        • Rtl
      • Software-verification
      • Math
      • Testing-utilities
    • Preprocessor

    Preprocessor-ifdef-minutia

    Subtle notes about or `define and `ifdef handling.

    There are many subtleties related to `define and `ifdef that make my head hurt.

    BOZO most of my testing was done on Verilog-XL before I really knew much about NCVerilog. It would be good to double-check all of these things on NCVerilog and make sure it behaves the same.

    Define is Lazy

    An important thing to realize is that the text which follows "`define foo" is not preprocessed once when it is read. Instead, it is separately preprocessed each time `foo is encountered. Hence, upon running

    `define foo 3
    `define bar `foo
    `undef foo
    `define foo 4

    the value of `bar will be 4.

    Includes are not followed if they are ifdefed away.

    On both Verilog-XL and NCVerilog, it appears that an `include directives within ifdef-ed away blocks are NOT expanded. An easy way to test this is by writing a file called endif.v which simply contains:

    `endif

    Then we can do things like this:

    `define foo
    `ifdef foo
      `include "endif.v"
    // the `ifdef has now ended

    And this:

    // suppose bar is undefined
    `ifdef bar
      `include "endif.v"
      // the `ifdef has not ended yet, so the include is not expanded
    `endif

    We think this is pretty reasonable so we mimic this behavior.

    We Prohibit Certain Directives In Defines

    In Verilog-XL, `define can interact with the `ifdef tree in subtle ways. For instance, Verilog-XL accepts the following input:

    `define condition 1
    `define myendif `endif
    `ifdef condition
       assign w1 = 1 ;
    `myendif

    Yet when `foo is used inside of an ifdef'd-away section, it is not expanded. And so, the above example becomes a parse error if you merely remove the `define condition 1 line.

    Another subtlety. As expected, defines found within ifdefed-away parts of the code have no effect. For example, if not_defined is not defined, then upon running

    `define foo 3
    `ifdef not_defined
       `define foo 4
    `endif

    the value of `foo will correctly be 3. Similarly, writing `undef foo in the not_defined block does not actually undefine foo. But the preprocessor is not mindlessly skipping text until an `else or `elseif is encountered. For example, the following is well-formed and does not result in a too-many-endifs warning.

    `ifdef not_defined
       `define myendif `endif
    `endif

    This is insane, so we prohibit things like `define myendif `endif by disallowing the use of built-in directives in macro text. Note that we still permit the use of `define foo `bar, with the same lazy semantics that Verilog-XL uses.

    We Prohibit Defining or Testing Built-in Directive Names

    We do not allow compiler directive names to be `defined, or to be used within ifdef, ifndef, or elsif directives. Why is this?

    Note that macro names can be simple or escaped identifiers. In Section 3.7.1, we are told that the leading backslash character and trailing whitespace are not considered part of an escaped identifier, and that the escaped identifier \cpu3 is to be treated the same as cpu3. Indeed, in Verilog-XL we find that the following works as expected:

    `define foo 3
    `define \bar 4
    
    assign w1 = `foo ;
    assign w2 = `\foo ;
    assign w3 = `bar ;
    assign w4 = '\bar ;

    In Section 19.3.1, we are told that all compiler directives shall be considered predefined macro names, and it shall be illegal to redefine a compiler directive as a macro name. And Verilog-XL seems to rightfully complain about things like:

    `define define 5
    `define ifdef 6

    And yet, Verilog-XL permits the following:

    `define \define 5
    `define \ifdef 6
    
    assign w1 = `\define ;
    assign w2 = `\ifdef ;

    While the following will be errors:

    assign w3 = `define ;
    assign w4 = `ifdef ;

    Should \define be treated differently from define? Maybe. After all, the point of escaped identifiers is probably to not clash with regular keywords. But on the other hand, if the predefined names are to be considered predefined, then shouldn't things like this

    `ifdef define

    always evaluate to true? But in Verilog-XL this is false unless you have done a `define \define like above. Verilog-XL also does not complain about `undef define, which seems strange.

    At any rate, to entirely avoid the question of what the right behavior is here, we simply prohibit the use of compiler directives, whether escaped or not, as names anywhere in defines, undefs, ifdefs, ifndefs, and elsifs. In practice this only prevents people from writing things like `define define and `ifdef undef, anyway, so this should not be too controversial.

    We make certain restrictions to disambiguate line continuations and comments.

    From 19.3.1, the macro text for a define is:

    • any arbitrary text specified on the same line as the macro name,
    • except that the sequence \<newline> may be used to extend the macro text across multiple lines,
    • and single-line comments are not to become part of the substituted text.

    On the surface, this is straightforward enough. But it is difficult to know exactly how comments and these line continuations are supposed to interact. And Verilog-XL, in particular, has some very strange and seemingly inconsistent rules:

    `define foo 5 // comment             (accepted)
             'h4
    
    `define foo 5 // comment \           (rejected)
             'h4
    
    `define foo 5 \/* comment */         (rejected)
             'h4
    
    `define foo 5 /* comment \           (accepted)
          */ 'h4
    
    `define foo 5 /* comment              (rejected)
          */ 'h4

    To prevent any amiguity, we prohibit any combination of comments and continuations that seems difficult to understand. In particular, we impose the following "cowardly" restrictions on macro text:

    1. Single-line comments are not allowed to end with \
    2. Block comments are not allowed to contain newlines
    3. The sequences \// and \/* are not allowed except within comments, string literals, and escaped identifiers

    These constriants make reading until the end of the macro text fairly complicated since we cannot stupidly read the text without interpreting it; rather we have to look for string literals, comments, escaped identifiers, etc. The goal is for everything we support will be interpreted in the same way by Verilog-XL and other tools.