Easy Tutorial
❮ Android Tutorial Webview Attention Android Tutorial Togglebutton Switch ❯

0.3 Verilog Coding Standards

Category Advanced Verilog Tutorial

Accidentally coming across an FGPA design I wrote years ago, the code style was passable, but the logical design was riddled with security risks. Many beginners write Verilog code based on C language thinking and style, leading to numerous non-standard common issues.

This section primarily summarizes some non-standard and dangerous Verilog designs. It mainly targets synthesizable digital designs; testbenches, which are simulation programs, generally have less stringent requirements.

Coding standards are different from coding styles. Coding styles are merely suggestions, and designers do not have to follow the coding style recommendations in this tutorial and can write code freely. As long as the logic is correct and the circuit is safe, even if the style is like flying willow catkins, as long as the compiler can compile and simulate normally, it's fine. Designers can proudly say, "Write your own code and let others guess!"

Coding standards are rules that must be followed to some extent, otherwise, they may affect the correctness of the digital circuit logic. Unless for special designs or when the designer is very familiar and confident, they can slightly deviate from Verilog coding standards. Otherwise, it is recommended to pay more attention to these standards during design, especially for beginners who are particularly prone to such issues.

On Initializing Values

Do not initialize variables when declaring them. If an initial value is set during variable declaration, the variable will have the expected initial value during simulation, but the initial value of the circuit after synthesis is uncertain. If the initial value of the signal affects the logic function, the simulation process may miss the opportunity to find logical errors due to insufficient verification. For example, the following description is not recommended:

reg [31:0] wdata = 32'b0 ;

Initial value assignments should be done during the reset state, and it is also recommended that register variables use a reset port to ensure that the system can return to its initial state upon power-up or disorder through a reset operation.

It is recommended to use positive edge logic for clocks and negative edge logic for resets during design. For detailed reset design, see 《5.1 Introduction to Reset》.

All signals in the statement block should be assigned initial values during reset, and do not miss any relevant signals.

always @(posedge clk or negedge rstn) begin
    if (!rstn) begin
        cnt  <= 'b0 ; // Missing initial value assignment for cout is dangerous
    end
    else if (cnt == 10) begin
        cnt  <= 4'b0 ;
        cout <= 1'b1 ;
    end
    else begin
        cnt  <= cnt + 1'b1 ;
        cout <= 1'b0 ;
    end
end

On Always Statements

Avoid using the rising and falling edges of the same clock in separate always blocks unless absolutely necessary, as this can introduce relatively complex clock quality and timing constraint issues.

// It is recommended to avoid using two always blocks with two clock edges
always @(posedge clk) begin
    a <= b ;
end
always @(negedge clk) begin
    c <= d ;
end

It is forbidden to use both edges of the clock as trigger conditions in one always block. Although compilation and simulation may proceed as per the designer's thoughts, such circuits are often not synthesizable, or the synthesized circuit functionality may not meet expectations.

// Forbidden to use both edges of the clock in one always block
always @(posedge clk or negedge clk) begin
    a <= b ;
end

It is forbidden to assign values to the same variable in two always blocks, a mistake many beginners often make.

// This design is incorrect
always @(posedge clk) begin
    a <= b ;
end
always @(negedge clk) begin
    a <= d ;
end

Do not include multiple parallel or unrelated conditional statements in one always block; use multiple always blocks instead.

When multiple parallel or unrelated conditional statements exist in one always statement, they are executed in parallel in the actual circuit synthesized or in the simulation results. However, the simulation process may be sequential, and delay information may lead to unpredictable error results. Moreover, this writing style is less readable and does not clearly delineate functional structures.

// Not recommended
always @(posedge clk) begin
    if (a == b)
        data_t1 <= data1 ;

    if (a == b && c == d)
        data_t2 <= data2 ;
    else 
        data_t2 <= 'b0 ;
end

// Recommended to split
always @(posedge clk) begin
    if (a == b)
        data_t1 <= data1 ;
end
always @(posedge clk) begin
    if (a == b && c == d)
        data_t2 <= data2 ;
    else 
        data_t2 <= 'b0
end

On Clocks and Asynchrony

Designs should preferably use synchronous design.

When asynchronous logic must be used, signals between different clock domains must be synchronized and cannot be directly used, otherwise metastable circuits will be generated. For specific synchronization implementations, refer to 《4.1 Synchronization and Asynchronization》 and subsequent related sections.

Avoid directly performing logical operations between clock signals and ordinary variable signals or detecting and judging clock signals by level. For example, the following descriptions are not recommended:

assign clk_gate = clk & clken ;
assign dout = (clk == 1'b1) ? din : 0 ;
always @(posedge clk) begin
    if (clk = 1'b1)
        data_t1 <= data1 ;
end

When selecting clocks under different conditions, do not use direct selection logic, as this can cause glitches. See 《5.4 Clock Switching》 for details.

On Synthesis

Under normal circumstances, do not directly use operations such as multiplication *, division /, and remainder % on signal variables. These operators, when synthesized, often result in structures and timing that are difficult to control. Optimized IP modules or integrated modules from the process library should be used instead. However, constant operations of the parameter type can use such operators, as the compiler calculates the results of constant operations at compile time and does not consume additional hardware resources.

Complete the conditions in the conditional statements of combinational logic, and list all sensitive signals in the always statements of combinational logic to avoid unintended latches. See 《Verilog Tutorial》 section 《6.5 Avoiding Latches in Verilog》 for details.

Consider whether the code can be synthesized into an actual circuit and what kind of circuit it will synthesize into during logical design. See 《9.2 Synthesizable Design》 for details.

On Instantiation

When instantiating, signals connected to input ports can be reg or wire type variables, while signals connected to output ports must be wire type variables. However, when declaring port signals, input signals must be wire type variables, and output signals can be reg or wire type variables.

When instantiating multiple modules, the module name comes first, followed by the instance name, and instance names must not be the same.

-0.1 Digital Logic Design

-0.2 Verilog Coding Style

-1.1 Verilog Gate Types

-1.2 Verilog Switch-Level Modeling

-1.3 Verilog Gate Delay

-2.1 Verilog UDP Basics

-2.2 Verilog Combinational Logic UDP

-2.3 Verilog Sequential Logic UDP

-3.1 Verilog Delay Models

-3.2 Verilog specify Block Statements

-3.3 Verilog Setup and Hold Time

-3.4 Verilog Timing Checks

-3.5 Verilog Delay Backannotation

-4.1 Verilog Synchronization and Asynchronization

-4.2 Verilog Clock Domain Crossing: Slow to Fast

-4.3 Verilog Clock Domain Crossing: Fast to Slow

-4.4 Verilog FIFO Design

-5.1 Verilog Reset Introduction

-5.2 Verilog Clock Introduction

-5.3 Verilog Clock Division

-5.4 Verilog Clock Switching

-6.1 Verilog Low Power Introduction

-6.2 Verilog System-Level Low Power Design

-6.3 Verilog RTL-Level Low Power Design (Part 1)

-6.4 Verilog RTL-Level Low Power Design (Part 2)

-7.1 Verilog Display Tasks

-7.2 Verilog File Operations

-7.3 Verilog Random Numbers and Probability Distribution

-7.4 Verilog Real to Integer Conversion

-7.5 Verilog Other System Tasks

-8.1 Verilog PLI Introduction

-8.2 Verilog TF Subroutines

-8.3 Verilog TF Subroutine List

-8.4 Verilog ACC Subroutines

-8.5 Verilog ACC Subroutine List

-9.1 Verilog Logic Synthesis

-9.2 Verilog Synthesizable Design

WeChat Subscription

English:

❮ Android Tutorial Webview Attention Android Tutorial Togglebutton Switch ❯