Verilog-Mode: Reducing the Veri-Tedium

Minor updates 2008-09-01

Wilson Snyder

wsnyder@wsnyder.org

SNUG San Jose 2001

Abstract

The Verilog Language has several design deficiencies which force users to enter and maintain redundant information, such as argument lists, sensitivity lists, and cross-module wire statements. Supporting this information leads to potential errors, lack of maintainability, and overall code bloat.

The author extended the Emacs Verilog-Mode package to provide AUTO features. These features look for /*AUTO*/ comments in the Verilog code, and expand them into the appropriate text. The AUTO features are implemented to be painless for even non-users; the code on disk is always valid Verilog code compatible with all existing tools. Though while greatly speeding coding for Emacs users, does not require Emacs to be used for later edits of the code.

Verilog-Mode allows the user to type:

module tedium (/*AUTOARG*/);
  input  in1,in2,in3,in4;
  input  out1,out2,out3,out4;

  /*AUTOREG*/
  /*AUTOWIRE*/

  always @ (/*AUTOSENSE*/) begin
    // complex logic here
  end
  
  sub sub1 (/*AUTOINST*/);
  sub sub2 (/*AUTOINST*/);
endmodule

And expand this with two keystrokes into a complete module.



1 Introduction

1.1 Is Verilog Tedious?

Verilog has a great deal of redundancy, which serves no useful purpose in most modules. Let's look at a small Verilog module, and consider what information in the module is redundant.

module tedium (i1, i2, o1, o2);
  input  i1,i2;
  output o1,o2;
  reg    o1;

  wire   o2;
  wire   inter1;

  always @ (i1 or i2 or inter1)
    o1 = i1 | i2 | inter1;
  
  sub1 sub1 (.i1 (i1),
             .i2 (i2),
             .o2 (o2),
             .inter1 (inter1));

  sub2 sub2 (.i1 (i1),
             .inter1 (inter1));
endmodule

Here the redundancies have been marked with light italics. Why is this information redundant?

  1. The argument list is a duplication of the input/output statements.
  2. Reg statements are needed for signals already `declared' as outputs.
  3. Wires need to be declared for interconnecting submodule signals.
  4. Sensitivity lists are needed for obvious combinatorial logic.
  5. Finally, name based sub-module instantiations are a duplicate of the sub-module's input/output statements. (Presuming the wire name matches the port name it connects to.)

It is surprising how much extra baggage Verilog requires. (Thank god we aren't coding in VHDL or it would be worse!)

1.2 Why reduce the Tedium?

Why should we care if we need to just do a little extra typing?

First, and most obvious, reducing the number of lines of code simply makes the code easier to comprehend. It's just easier to understand if meaningless information is removed.

Next, if a mistake is made in writing or maintaining that extra code, we have more spins through our compiler or lint program. That takes time.

If we instantiate the same module multiple times, we are at great risk of cut-and-paste errors. It's also very difficult to understand how bus bits are spread across multiple instantiations. (Does bit 0 always come from instantiation 0?)

Worse, sensitivity lists are just plain hard to get right in big blocks. If you omit a signal from the sensitivity list and didn't run a lint tool it's likely to take hours to debug.

Finally, it's too hard to change, add, or delete a signal through the hierarchy. If the signal goes up two levels and back down two levels, you have approximately 16 lines to edit.

1.3 Design goals

How can we reduce this tedium?

We could simplify the language itself. This is certainly cleanest; Verilog 2000 has many features that reduce tedium, including always @ (*) for eliminating sensitivity lists. However, it faces the hurdle of requiring an all new tool suite; until all tools you are using support it, it's effectively useless.

We could write a preprocessor. That seems ok, but it would be required to be run the preprocessor in front of all Verilog programs, and more importantly every user of the code would be required to have the tool. Because of this, if you are providing Intellectual Property to others, a preprocessor probably isn't an option.

What we would really like would be for legal Verilog to come into the tool, and legal Verilog to come out, so the file on the disk is always legal. Only when the code is being edited should the code possibly not be valid Verilog code. Thus someone not using our tool always has legal and complete source code.

1.4 The solution: Use comments

How do we have valid Verilog code come in and out, but still save all of that typing? We'll use comments to indicate that the text following the comment should be automatically computed.

Take a simple Verilog program:

always @(/*AS*/) begin
   if (sel) z = a;
   else     z = b;
end

We'll make /*AS*/ a special comment the program can look for. When it finds it, the program will scan the block after the comment and compute the sensitivity list.

Running the program we'll get back:

always @(/*AS*/a or b or sel) begin
   if (sel) z = a;
   else     z = b;
end

Where the sensitivity list was added. Then the user can edit this code to make a RTL change:

always @(/*AS*/a or b or sel) begin
   if (sel) z = a;
   else     z = s2?c:d;
end

And rerun the program to get back the right sensitivity list:

always @(/*AS*/a or c or d
         or s2 or sel) begin
   if (sel) z = a;
   else     z = s2?c:d;
end

For readability, we'll also have a way to back out all computed information to make the code easy to read again:

always @(/*AS*/) begin
   if (sel) z = a;
   else     z = s2?c:d;
end

1.4.1 How to implement this?

Expanding the comments, which we'll call the AUTOs from here out, is best done in the editor. This lets the user expand and remove them at will, and get instant feedback as to if the AUTOs are doing what is desired. Most importantly, when the code is saved, it can be expanded on the way out, accomplishing our goal of the code on disk always being valid.

When editing, it's also nice to have automatic indentation and highlighting of comments and such. Thus, we'd like a standard language mode as the basis for the program.

Rather then start from scratch, the author started with the leading Verilog language mode, Verilog-Mode by Michael McNamara mac@versity.com. Upon this base, parsing and expansion of the AUTOs were added.





2 General usage

I'll now discuss each feature of the AUTOs and how to use them.

Through this section, I'll refer to a couple of key sequences, as keys are easier to represent in a document, and quicker for power users. However, those that prefer the mouse can execute this command from under the Verilog option in the menu bar. Likewise all commands and documentation can be found under the menu.

2.1 Batch invocation

For those that use vi, or have a script generating code, it is useful to be able to expand the automatics from the shell. Batch invocation is done with the shell command:

emacs --batch filename.v -f verilog-auto -f save-buffer

This invokes Emacs in batch mode (no window opened), reads the file, expands the automatics, then finally saves the file.

If you have a large site initialization file that is slow, you can be more explicit (and faster) by loading Verilog-Mode directly with the below. However only using no-site-file if you have to, as you'll need to check your site file for any verilog- variable settings and reproduce them on the command line or in a new startup file.

emacs --batch --no-site-file -l verilog-mode.el 
      filename.v -f verilog-auto -f save-buffer

You'll find batch mode very valuable when you are writing a perl script or something to generate Verilog code. Simply have your script print out the AUTO comments and let Emacs worry about the sensitivity lists and such. It will make your script a lot simpler.

2.2 Expanding Autos

There are only three key sequences that implement all of the important features. The first two are for expanding the AUTOs, and the final for deleting them.

Once you've added the AUTO comments for the first time, and/or wish to update them, the keys C-c C-a or M-x verilog-auto will expand the automatics.

After trying this a couple of times, you'll probably get into the hang of expanding the automatics, then saving the file, then running your lint program. Since this sequence is so common, C-c C-s or M-x verilog-auto-save-compile will do all three: expand automatics, save the buffer, and run the compiler (which should be setup to be a linting tool.) This is easy to remember as being similar to the standard save-buffer keys, C-x C-s.

2.3 Deleting Autos

If you wish to look at the smaller version of the file, or are planning a large number of edits and want to remove the extra baggage, all of the automatics can be deleted with C-c C-d or M-x verilog-delete-auto. The same C-c C-a or M-x verilog-auto discussed above will get the expanded results back.

2.4 Sensitivity Lists

The first AUTO comment addresses the biggest tedium in Verilog; sensitivity lists. Verilog-Mode will replace /*AUTOSENSE*/, or /*AS*/ for short, with the sensitivity list for the block after that comment. For example:

always @ (/*AUTOSENSE*/) begin
   outin = ina | inb;
   out = outin;
end

Typing C-c C-a will make this into:

always @ (/*AUTOSENSE*/ina or inb) begin
   outin = ina | inb;
   out = outin;
end

Verilog-Mode understands that signals that are generated within the same always block (outputs of that block) are not placed into the sensitivity list, so out and outin do not appear in the list. The Verilog language doesn't understand memories (multidimensional arrays) in sensitivity lists either, so AUTOSENSE will exclude them and add a /*memory or*/ comment as a reminder to you that memory changes won't activate the block.

In the example we used a begin/end pair after the always. This makes sure Verilog-Mode recognizes where the block ends, and gets around a bug in early versions of Verilog-Mode. (The latest version hasn't been fooled yet, but it's better to be safe with begin/end or case/endcase pairs in case older versions of Verilog-Mode are encountered).

2.4.1 Constant signals

AUTOSENSE probably won't do what you expect the first time you use a constant inside your block:

always @ (/*AUTOSENSE*/ina or inb or `constant) begin
   out = ina | inb | `constant;
end

AUTOSENSE cannot always determine if the defined value for `constant is a numeric constant or a signal. There are a number of fixes for this:

  1. Use the AUTO_CONSTANT declaration anywhere in the module (the parenthesis are required):
    /* AUTO_CONSTANT ( `this_is_really_constant_dont_autosense_it ) */
    
  2. Use a parameter declared in the module rather then a define, this will automatically be understood as a constant. (It has the added advantage of being local in scope, rather then polluting the global name space.)
  3. Use verilog-read-defines or verilog-read-includes as described below in the Instantiation section.
  4. Set verilog-auto-sense-defines-constant, this will mark all defines as constants. This is best done at the bottom of the file:
    // Local Variables:
    // verilog-auto-sense-define-constant:t
    // End:
    
    You need to re-visit (type C-x C-v RET) the file after changing any such local variable block; Emacs only parses it when the file is read in.

2.5 Argument Lists

Argument lists are created with /*AUTOARG*/. This parses the input/output/inout statements and generates the argument list. For example:

module ex_arg (/*AUTOARG*/);
   input i;
   output o;
endmodule

Typing C-c C-a will make this into:

module ex_arg (/*AUTOARG*/
  // Outputs
  o,
  // Inputs
  i);

   input i;
   output o;
endmodule

Concatenation and outputting partial busses is not supported, nor are `ifdefs and such. You can work around that by placing ports between the ( and /*AUTOARG*/. Verilog-Mode will presume these to be predeclared and will not be redeclared by AUTOARG. Avoid doing this if you can, as it will just lead to more ifdefs if this module is then used in a /*AUTOINST*/.

module ex_arg (
`ifdef need_x_input
  x,
`endif
  /*AUTOARG*/
  // Outputs
  o,
  // Inputs
  i);

`ifdef need_x_input
  input x;   // This is an optional input, if `need_x_signal is defined
`endif

  ...

Since the generation of arguments is so foolproof, you'll probably never need to edit or think about a module's argument list again. AUTOARG is also an excellent first thing to try on an existing module; it's pretty obvious what it does, and only a compile is needed to insure it tests the same as the original.

2.6 Instantiations

Instantiations are the most frustrating part of Verilog, as each signal must be listed three times; once as an input/output statement in the submodule, once in the instantiation's pin name, and once in the instantiation's connected wire name.

AUTOINST understands how to find a submodule, and will make the name based instantiation for you.

Assume that you have a submodule, stored in the file fanout.v:

module fanout (o,i)
   input i;
   output [31:0] o;
   wire [31:0] o = {32{i}};
endmodule

Now you want to use that submodule in an upper level module:

module ex_inst (o,i)
   input i;
   output [31:0] o;
   fanout fanout (/*AUTOINST*/);
endmodule

Typing C-c C-a will make the upper module into:

module ex_inst (o,i)
   output o;
   input i;
   fanout fanout (/*AUTOINST*/
                    // Outputs
                    .o (o[31:0]),
                    // Inputs
                    .i (i));
endmodule

Where the list of inputs and outputs came from reading fanout.v's input and output statements.

2.6.1 Exceptions to direct connects

AUTOINST presumes a one-to-one port name to signal name mapping. This is the most common case.

Unless you are instantiating a module multiple times, or the module is a generic part like an adder, do not change signal names across the hierarchy. It just makes for unmaintainable code. Generally, I rename either the parent or child to be consistent. To do this, try my vrename from http://www.veripool.org. Vrename makes it a 30 second job to fix up all of the name mismatches, and will give you lots of downstream benefits.

When you need to violate this suggestion the simplest is to specify the port directly before the /*AUTOINST*/. Any ports defined before the /*AUTOINST*/ are not included in the list of automatics. You should also put a // Input or // Output comment before the ports so that AUTOWIRE, discussed below, will know in which direction the signal goes.

fanout fanout (
               // Inputs
               .i          (my_i_dont_mess_with_it),
               /*AUTOINST*/
               // Outputs
               .o          (o[31:0]));

2.6.2 Templates

If the same module is instantiated multiple times, you can use a /*AUTO_TEMPLATE*/ to specify the exceptions just once. Create a commented out template with AUTO_TEMPLATE as the instantiation name:

/* psm_mas AUTO_TEMPLATE (
        .PTL_MAPVALIDX          (PTL_MAPVALID[@]),
        .PTL_BUS                (PTL_BUSNEW[]),
        ); */

The module name in the template must be the same as the module name in the instantiation. Only signals that must be different for each instantiation need to be listed.

It's important to have one port per line, ending in a comma or ); just like AUTOINST produces. In fact, it's easiest to generate the AUTO_TEMPLATE by making an AUTOINST, expanding the autos, then cutting out the lines Verilog-Mode inserted at the AUTOINST and pasting them into the template.

Templates go above the instantiation(s). When an instantiation is expanded Verilog-Mode simply searches up for the closest template. Thus you can have multiple templates for the same submodule, just alternate between the template for an instantiation and the instantiation itself.

The above psm_mas template will convert:

psm_mas ms2 (/*AUTOINST*/);

Typing C-c C-a will make this into:

psm_mas ms2 (/*AUTOINST*/
    // Outputs
    .INSTDATAOUT     (INSTDATAOUT),
    .PTL_MAPVALIDX   (PTL_MAPVALID[2]),   // Templated
    .PTL_BUS         (PTL_BUSNEW[3:0]),   // Templated
    ....

The @ character is some very useful magic. The @ will be replaced by the first digits in the instantiation's name. Note the @ character was replaced with the 2 from "ms2". Also, those ports not listed in the template are assumed to be direct connections.

The AUTOs replace a [] in the template (a "null" bus subscript) by the bit range that the submodule needs, or nothing if it is a single bit port. Note how PTL_BUSNEW[] became PTL_BUSNEW[3:0] above. Generally using [] is better then putting the bits into the template, because if the submodule changes the bit-range in its input or output statement, it will propagate that change to the parent module automatically. (Which is the whole point of the AUTOs, hiding of information and automating affects of changes.)

2.6.3 Lisp templates

Specifying a simple wire name in an AUTO_TEMPLATE isn't always enough, especially when spreading bits across multiple instantiations. Thus Verilog-Mode allows you to write a program to compute the name of a wire to connect to a given port:

/* psm_mas AUTO_TEMPLATE (
        .PTL_MAPVALIDP1X  (PTL_MAPVALID[@"(% (+ 1 @) 4)"]));
*/

submod i0 (/*AUTOINST*/);
submod i1 (/*AUTOINST*/);
submod i2 (/*AUTOINST*/);
submod i3 (/*AUTOINST*/);

When the syntax @"( ... )" is encountered, the expression in quotes will be evaluated as an Emacs Lisp expression, with @ replaced by the instantiation number. Lisp programming is fairly straight forward, just put the operator first (prefix notation). Any double-quotes inside the expression itself will need to be quoted with a leading backslash \".

The MAPVALIDP1X example above would put [@+1 modulo 4] into the brackets. Thus instantiation i0 gets PTL_MAPVALID[1], i1 gets PTL_MAPVALID[2], i2 gets PTL_MAPVALID[3], i3 gets PTL_MAPVALID[0]. (The coder picked the port name MAPVALIDP1X to mean MAPVALID plus 1 instantiation number.) This type of thing is very useful for barrel shifters and the like.

Normal lisp variables can be used in the AUTO_TEMPLATE expressions. In addition some special variables are defined:

vl-name is the name portion of the input/output port (`PTL_MAPVALIDP1X'). vl-bits is the bus bits portion of the input/output port (`[2:0]').

Furthermore, verilog-read-defines, described below, will make a vh-{definename} variable for every define in the module. Even better, any comments of the form:

        /*AUTO_LISP(setq foo 1)*/

will evaluate any Lisp expression inside the parenthesis between the beginning of the buffer and the point of the AUTOINST. This allows variables to be changed between each instantiation, and very complex templates to be made, including string based substitutions.

2.6.4 Regexp templates

Sometimes fixed port names in AUTO_TEMPLATES aren't enough, it would be useful to match many ports with one template line. The most common case is when bit blasting or changing naming conventions across a large number of pins, such as at the top of a chip.

An AUTO_TEMPLATE entry of the form:

    .pci_req\([0-9]+\)_l   (pci_req_jtag_[\1]),

applies an Emacs style regular expression search. This example matches any port beginning with "pci_req" followed by numbers and ending in "_l". That port is connected to the pci_req_jtag_[] wire, with the bus subscript coming from what matches inside the first set of \( \). Thus pci_req2_l connects to pci_req_jtag_[2].

Since matching \([0-9]+\) to port names is so common and ugly to read, a @ does the same thing. (Note this is different from the instantiation number, which is what @ does on the right side of the template.) Thus the below template is equivalent to the above template:

    .pci_req@_l      (pci_req_jtag_[\1]),

Here's another example to remove the _l, perhaps because the naming conventions specify _ alone to mean active low. Note the use of [] to determine the bus subscript automatically:

    .\(.*\)_l        (\1_[]),

Here's a final template that is very useful:

/* submod AUTO_TEMPLATE (
      .\(.*[^0-9]\)@  (\1[\2]),
      );*/

It says to take a port of the form lettersDIGITS and convert it to letters[DIGITS], conveniently vectorizing the signal. The [^0-9] is needed because otherwise .* could match trailing digits.

2.7 Interconnection Wires

When interconnecting modules, wire statements are required for bussed outputs of submodules. /*AUTOWIRE*/ will declare wires for the outputs of all submodules. This is especially nice for signals that cross between two submodules and are not used in the top module itself.

AUTOWIRE assumes that either /*AUTOINST*/ was used, or you manually added // Output comments to the instantiations. For example:

module top (o,i)
   output o;
   input i;

   /*AUTOWIRE*/

   inst inst   (/*AUTOINST*/);
   other other (/*AUTOINST*/);
endmodule

Typing C-c C-a will make this into:

module ex_wire (o,i)
   output o;
   input i;

   /*AUTOWIRE*/
   // Beginning of automatic wires
   wire [31:0]  ins2oth;    // From inst of inst.v
   wire [31:0]  oth2ins;    // From other of other.v
   // End of automatics

   inst inst   (/*AUTOINST*/
                // Outputs
                .ins2oth  (ins2oth[31:0]),
                .o        (o),
                // Inputs
                .oth2ins  (oth2ins[31:0]),
                .i        (i));

   other other (/*AUTOINST*/
                // Outputs
                .oth2ins  (oth2ins[31:0]),
                // Inputs
                .ins2oth  (ins2oth[31:0]),
                .i        (i));

endmodule

Cross and oth2ins are declared because they are outputs of submodules. It also adds a nice comment that makes it easy to understand where the wires are coming from. Even if bus bits come from multiple submodules, or the wires were manually declared, AUTOWIRE will do the right thing.

2.8 Registered Outputs

If a module output comes from a register, the signal needs to be declared as both a register and as an output. AUTOREG will read the output declarations and make the register declaration for you. As would be expected, if the output comes from a submodule or wire, the reg statement isn't added. For example:

module ex_reg (o,i)
   output o;
   input i;

   /*AUTOREG*/

   always o = i;
endmodule

Typing C-c C-a will make this into:

module ex_reg (o,i)
   output o;
   input i;

   /*AUTOREG*/
   // Beginning of automatic regs
   reg    o;
   // End of automatics

   always o = i;
endmodule

Where o needs to be both an output and a register.

2.9 Shell Modules

Often one module needs an identical port list as another module. This is needed to produce a shell around the original module, or to create a null module. /*AUTOINOUTMODULE(module)*/ copies the input/output/inout statements from the specified module and inserts it into the current module. Any I/O which were already defined in the current module will not be redefined.

For example:

module ex_shell (/*AUTOARG*/)
   /*AUTOINOUTMODULE("ex_main")*/
endmodule

module ex_main (i,o,io)
  input i;
  output o;
  inout io;
endmodule

Typing C-c C-a will make this into:

module ex_shell (/*AUTOARG*/i,o,io)

   /*AUTOINOUTMODULE("ex_main")*/
   // Beginning of automatic in/out/inouts
   input i;
   output o;
   inout io;
   // End of automatics

endmodule

2.10 State Machines

When you are debugging a state machine in waves, it's very nice to have a signal you can see with the names of the states in it. Likewise, if using a $display statement, you'd like to have a string with the state name. /*AUTOASCIIENUM(in,out,prefix)*/ takes a set of parameters and makes a block to decode the state vector. For example:

//== State enumeration
parameter [2:0] // synopsys enum state_info
                SM_IDLE =  3'b000,
                SM_SEND =  3'b001,
                SM_WAIT1 = 3'b010;

//== State variables
reg [2:0]       /* synopsys enum state_info */
                state_r;  /* synopsys state_vector state_r */
reg [2:0]       /* synopsys enum state_info */
                state_e1;

//== ASCII state decoding
/*AUTOASCIIENUM("state_r", "_stateascii_r", "sm_")*/

Typing C-c C-a will make this into:

... same front matter ...

//== ASCII state decoding
/*AUTOASCIIENUM("state_r", "_stateascii_r", "sm_")*/
// Beginning of automatic ASCII enum decoding
reg [39:0]           _stateascii_r;          // Decode of state_r
always @(state_r) begin
   casex ({state_r}) // synopsys full_case parallel_case
     SM_IDLE:  _stateascii_r = "idle ";
     SM_SEND:  _stateascii_r = "send ";
     SM_WAIT1: _stateascii_r = "wait1";
     default:  _stateascii_r = "%Erro";
   endcase
end
// End of automatics

Here's how to use it:

  1. Declare state parameters as an enumeration using the synopsys enum comment. The comment must be between the keyword and the symbol. (Annoying, but that's what Synopsys's dc_shell FSM reader requires.)
  2. Tag registers to which that enum applies with the same enum. Synopsys also suggests labeling state vectors, but Verilog-Mode doesn't care.
  3. Add the /*AUTOASCIIENUM(in,out,prefix)*/ comment.
    in
    The first parameter is the name of the signal to be decoded.
    out
    The second parameter is the signal name to store the ASCII code into. For the signal foo, I suggest the name _foo__ascii, where the leading _ indicates a signal that is just for simulation, and the magic characters _ascii tell waveform viewers like my Dinotrace to display in ASCII format.
    prefix
    The final optional parameter is a string which will be removed from the state names. This simply reduces the width of the ascii decoding, so it's more likely to fit on the screen in a waveform viewer.

After expanding, you'll get the block and the decoded signal you need. Note that the vector _stateascii_r is declared to the exact width needed to fit the ascii for the largest state.

3 General Tips

This section covers a couple of general tips for using the AUTOs.

3.1 Finding Modules

If you've read through the instantiation section, you might be wondering how Verilog-Mode knows where to find a given module declaration.

Verilog-Mode looks first in the current file, that's in case you have multiple modules defined there. Then it looks for the module name with each extension in verilog-library-extensions appended, normally a `.v'. Finally it searches in each directory defined in verilog-library-directories.

Thus if you have a top level module that needs to find submodules in subdirectories, you need to tell Verilog-Mode to look in the subdirectories. The best way to do this is to define the library variables at the end of each Verilog file that needs them:

// Local Variables:
// verilog-library-directories:("." "subdir" "subdir2")
// verilog-library-files:("/some/path/technology.v" "/some/path/tech2.v")
// verilog-library-extensions:(".v" ".h")
// End:

Emacs automatically parses this section and sets the appropriate variables. Since Emacs doesn't notice edits to them until the file is re-read, remember to C-x C-v RET if changing local variables!

These three variables have the following effects:

verilog-library-directories
The variable verilog-library-directories contains a list of directories in which to look for the module. Having at least the current directory (the default) is a good idea.
verilog-library-extensions
The variable verilog-library-extensions contains a list of filename extensions to try to append to module names to generate file names. Normally just ".v".
verilog-library-files
The variable verilog-library-files contains a list of files that will be searched in entirety for modules. This is usually a complete path to a technology file with many standard cells defined in it.

3.2 Defines

When using AUTOINST or AUTOSENSE, it's sometimes important for Verilog-Mode to know what defines are defined in the current file. This allows Verilog-Mode to properly resolve modules and know which defines represent constants.

If macros are defined earlier in the same file and you want their values, you can read them automatically:

// Local Variables:
// eval:(verilog-read-defines)
// eval:(verilog-read-defines "group_standard_includes.v")
// End:

The first eval will read all of the `defines in the current file. The second eval will read the defines in a specific file, such as if there is a standard include file that does not have a specific `include in the module itself.

Defines must be simple text substitutions, one on a line, starting at the beginning of the line. Any ifdefs or multiline comments around the define are ignored.

3.3 Include files

For speed reasons, Verilog-Mode doesn't automatically read include files. This means that constants defined in an include file won't be known as constants for AUTOSENSE. This can be fixed by telling Emacs to read the includes when the file is read:

// Local Variables:
// eval:(verilog-read-includes)
// End:

This will parse the file just read in, and read any `includes that it finds in that file. Remember the C-x C-v RET after changing local variables!

It is good to get in the habit of including all needed files in each .v file that needs it, rather then waiting for compile time. This will aid Verilog-Mode, Verilint, and readability. To prevent defining the same variable over and over when many modules are compiled together, put a test around the entire contents of each include file:

        // include if not already included
        `ifdef _FOO_V `else
         `define _FOO_V
         ... contents of file
        `endif // _FOO_V

This is standard procedure for C header files, and should become standard practice in Verilog for the same reasons.

4 Getting Verilog-Mode

The best way to explore Verilog-Mode is to get it, and try a couple of simple features like AUTOARG and AUTOSENSE. You'll find more and more AUTOs creeping into your code, and you'll soon join the thousands of engineers that would never work without them.

Verilog-Mode comes with VCS, but that version is fairly old, and unless you've recently downloaded the latest (version 3.50 at this writing), you should might as well download the latest before getting started. To download, follow the link off the author's site: http://www.veripool.org.

Please report bugs to the Verilog-Mode GNATS server, verilog-mode-bugs@surefirev.com.

To contact the author directly, email wsnyder@wsnyder.org.