VerilogCodingGuidelines

Ali Raheem edited this page Mar 21, 2018 · 4 revisions

Table of Contents

Verilog coding guidelines

Updated 16:36, 22 January 2007 (PST)

This is a GUIDE for writing Verilog for synthesis. As such it is a list of suggestions and recommendations, not rules. Some suggestions are very subjective while others are almost mandatory - i.e. you should have a good reason for not following them.

Naming

Module/instance naming

You are free to name your modules as you please, provided that the following conditions are met:

  • The final top level modules should be the chip name with _top appended, e.g. unet_top.v .
  • When instantiating a module the instance name should be either:
    • identical to the module name if the module name adequately describes the purpose. e.g. sram_output_fifo sram_output_fifo (...);
    • the module name followed by a descriptive subscript. e.g. fifo fifo_sram_output (...);

Signal naming

  • All signals are lowercase alpha, numeric and underscore only. (Exceptions permitted for external pins and auto-generated code.)
  • Avoid active low signals in the core. If you must have them then append _n to the signal name. e.g. active_low_b
(Active low signals at the pins are fine but invert them in the core before using them.)
  • Buses are numbered high order to low order: bus[31:0]
  • Array locations are numbered low to high. e.g. 2048x32 bit RAM:
 reg [31:0] mem_array [0:2047];
  • Don't try to indicate the direction of the signal in the name: e.g. my_signal_in or my_signal_i is bad . Just use my_signal . This makes it much easier to hook up blocks.
  • Do use the same name for the signal at all levels of hierarchy.
  • Do indicate the direction of a signal as a comment in the signal list:
 my_module (
     my_signal,  //I: Input from other_module
 );

Constant naming

  • Use capitals to identify constants: e.g. DEBUG , IDLE

Indenting

  • Use three spaces per indentation level. Expand tabs to spaces to prevent indentation changing based upon editor settings.
Vim users can place the following modeline near the top or bottom of each file:
 // vim:set shiftwidth=3 softtabstop=3 expandtab:
Emacs users
  • Indent begin/end statements as follows:
 if (this) begin
     do something;
 end
 else begin
     do something else;
 end

Commenting

  • Comment your code. Someone will be coming back to this code in 6 months time, and that person will probably be you .
  • When entering multi-line comments, try to use the "/*..*/" commenting rather than putting "//" in front of every line. It makes editing much easier.
  • Add the following header to the top of all source code written by us (change the details as necessary):
 ///////////////////////////////////////////////////////////////////////////////
 // vim:set shiftwidth=3 softtabstop=3 expandtab:
 // $Id: reg_file.v 916 2006-04-20 23:23:25Z bob $
 //
 // Module: reg_file.v
 // Project: CPCI (PCI Control FPGA)
 // Description: Register file for access via PCI
 //
 //
 // Change history: 8/18/04 - Implemented DWORD0 (Revision/Version ID)
 //                 10/29/04 - Made the RESET signal last longer than
 //                 a single clock
 //                 01/08/05 - dma_rd_mac is now an input as round-robin
 //                 lookup is used
 //                 01/13/05 - split dma_intr into read and write sigs
 //
 ///////////////////////////////////////////////////////////////////////////////
Note: We probably need to add copyright info to the header as well.

Module declaration/instantiation

  • Each module should be defined in a separate file.
  • Use Verilog 2001 ANSI-C style port declarations:
    output reg signal_C,
 
    input clk
 );
  • Declare inputs and outputs one per line. It makes grep 'ing so much easier. If I want to find who drives a signal in code written this way, I can grep for " output.*signal ". It also gives you a handy place to put a comment.
  • Group signals logically by their function (e.g. keep DDR signals together). Place the 'miscellaneous' signals at the end of the signal list. This will include clk , reset and anything else that generally has a high fanout and goes between many modules.
     signals_to_from_block_B, // description
 
     input reset,
     input clk
 );
  • Instantiate signals one per line whether as inputs or when instantiating a block—it makes it easier on the scripts!
  • Don't instantiate modules using positional arguments. Always use the dot form:
 my_module my_module(
     .signal (signal),
     .a_bus  (a_bus),
     ...
 );
(There are some utilities for building instantiations of modules that work if the signal names are consistent between levels.)
  • Use explicit in-line parameter redefinition when overriding parameters:
 my_module my_module  '''#(.WIDTH(32))''' (
     ...
 );

Clocking

  • Core clock signal for a module is ' clk '.
  • All other clocks should have a description of the clock and the frequency embedded—it makes life easier for the synthesis person. e.g. clk_ddr_400
  • Keep to one clock per module if possible. (It's easier to understand and it will synthesize much faster.)

Synchronization/clock domain crossing

  • If you have signals that need to be synchronized (cross asynchronous clock boundaries) then name the synch flops as synch_<something> . e.g.
 reg synch_stage_1, synch_stage_2;
These can be given special treatment for simulation, and you can apply automatic checks to ensure all synch domains have synch flops.
Corollary: Don't use ' synch ' in any other flop names.
  • Avoid mixing synchronization/domain crossing code with general logic. Clearly delineate the code in a large module with other logic or place in a separate module.
  • The statements " input " and " output " will default their arguments to wires, so there is no need to put a wire statement in the code for anything that is an input or an output. Other wires (hookup wires) need to be declared only if they are multi-bit, although some people like to declare the single-bit ones as well.

Reset

Reset signal is:

  • called ' reset '
  • active high within the core
  • synchronous

Assignment statments

  • Sequential elements MUST only have non-blocking assignments (<=)
  • Combinatorial should only have blocking assignments (=)
  • Don't mix blocking and non-blocking assignments within a code block.

Parameters, defines and constants

  • Do parameterize modules if appropriate and if readability is not degraded.
  • Propagate parameters through the hierarchy:
 #(parameter ADDR_WIDTH = 10,
   parameter DATA_WIDTH = 32)
 ( input [DATA_WIDTH-1:0] data,
   input [ADDR_WIDTH-1:0] addr,
   ...
 );
 ...
 /* instance using the same parameters */
 b_module b_module_0
 #(.ADDR_WIDTH(ADDR_WIDTH),
   .DATA_WIDTH(DATA_WIDTH))
 ( .data(data)...);
  • Place all global `define s in external defines files that are included in the project.
  • Do not declare `define statements in individual modules.
  • Use localparam for constants that should not be redefined from outside of the module. E.g. the states for a state machine:
 localparam IDLE    = 3'd0; // Oven idle
 localparam RAMP_UP = 3'd1; // Oven temperature ramping up
 localparam HOLD    = 3'd2; // Hold oven at bake temperature
 ...

Debugging & assertions

  • Group your assertions at the end of the module, surrounded by synthesis translate_off and synthesis translate_on :
 // synthesis translate_off
 always @(posedge clk)
    // Verify that the length never exceeds 10
    if (len > 10)
       $display($time, " ERROR: Length exceeds 10 in %m");
 // synthesis translate_on
 
 endmodule

State machines

  • Simple state machines: feel free to combine flops with next-state combinational logic
  • Long/complex state machines: separate flops from combinational/next state logic. e.g.
 always @*
 begin
     // Default to current state
     state_nxt = state;
     addr_nxt = addr;
 
     if (reset)
     begin
         state_nxt = START_STATE;
         addr_nxt = 'h0;
     end
     else
     begin
         case (state)
             START_STATE: begin
                 if (ready)
                     state_nxt = GO_STATE;
             end
             ...
         endcase
     end
 end
  • Assign default values at the start of conditional statements: this tends to shorten the code (more readable) and helps to ensure that everything always gets a value.
    case (expr)
       state_1 : ... // if a should be default_a then we dont put it here.
       state_2 : ...
    endcase

General Verilog coding

  • Synthesizable logic goes in leaf modules.
    • As much as possible, try to keep all synthesizable code in leaf modules, and use hierarchical modules only to hook things up. A single "!" at core can wreak havoc.
  • Use @* for the sensitivity list for combinational logic always blocks:
 always @*
    a = b + c;
  • Don't try to write ultra-slick Verilog—it makes it harder to read.
  • Avoid for loops—they are usually difficult to understand. Sometimes they are really useful: e.g. unrolling bit expressions that involve other bits.
  • = generate = blocks are encouraged for generating instances/blocks of code:
 generate
    genvar i;
    for (i = 0; i < 4; i = i + 1) begin: par_gen
       parity8 parity(
          .data(wr_data[(i * 8) +: 8]),
          .parity(wr_par[i])
       );
    end
 endgenerate
  • Don't use the `include directive in synthesizable code. This is never necessary and introduces synthesis dependencies that are difficult to track.
    • If an include absolutely cannot be avoided then surround included file with `ifdef , `define and `endif directives.
  • No tri-states in the core! Only tri-state I/Os!
  • Use small-ish modules—try to keep modules small and readable.

Synthesis

  • NO LATCHES! Check the results of synthesis and ensure you do not have any inferred latches—it usually means you missed something in your coding.
  • No asynchronous logic/combinatorial feedback loops/self timed logic.
  • Try to flop all inputs and outputs to a block—it makes it much easier to set timing constraints. This means you will have to think about how modules are grouped for synthesis. It's fine not to have flops in a module if that module is going to be synthesized with the modules that do have the relevant source/sink flops.
  • All non data-path flops must have a reset.
  • All data-path flops must reset within 5 clocks. Usually this means that you only need to reset the input pipeline flops, and subsequent flops will reset within the specified number of clocks. If you're not sure then reset them explicitly.
  • If you do have some flops with reset and some without, then don't put them both in the same block of code:
BAD:
 always @(posedge clk) 
     if (reset) 
         stage_1 <= 'h0;
     else begin
         stage_1 <= input;
         stage_2 <= stage_1;
     end
This causes reset to be used as an enable on stage_2. Move stage_2 to a separate block or take it out of the if-then-else.
GOOD:
 always @(posedge clk)
    stage_2 <= stage_1;
  • Specify ALL cases in a case statement (use default if you don't need them all).
Bear in mind that XST will prioritize in top-to-bottom order.
  • Don't use casex and casey
  • Do not use pragmas for case: parallel_case full_case
  • Keep it simple. If you cannot envisage the final synthesized logic for your code then XST will probably have a hard time.
  • Don't mix hand-instantiated circuitry with RTL

Acknowledgements, further reading, and more

These guidelines are based on a document written by Greg Watson.

Many of these recommendations are courtesy of Paul Zimmer.

For further reading on Verilog styles, synthesis techniques, useful scripts, etc I recommend the following papers:

Many of the above papers appeared at SNUG: http://www.snug-universal.org/papers/papers.htm
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.