Register Transfer Level (RTL)

Register Transfer Level (RTL)#

Register Transfer Level (RTL) design focuses on the flow of data between registers and the logic operations performed on that data. It is critical in hardware description languages (HDL) such as Verilog and VHDL, where the code describes the behavior of digital circuits at the register level. In this project, we follow strict RTL guidelines to ensure clarity, reliability, and maintainability of the hardware design.

Guidelines#

  • Always Use Non-blocking Assignments for Sequential Logic: For sequential logic (inside always blocks sensitive to a clock edge), use non-blocking assignments (<=) to ensure the correct behavior of registers and avoid race conditions.

    Correct Example:

    always @(posedge clk) begin
      if (reset)
        counter <= 0;
      else
        counter <= counter + 1;
    end
    

    Incorrect Example:

    always @(posedge clk) begin
      if (reset)
        counter = 0;  /* Blocking assignment, incorrect for sequential logic */
      else
        counter = counter + 1;
    end
    
  • Use Blocking Assignments for Combinational Logic: For combinational logic, use blocking assignments (=) within always blocks. This ensures that the logic is evaluated sequentially, and the output reflects the latest input conditions.

    Correct Example:

    always @(*) begin
      result = a + b;  /* Blocking assignment for combinational logic */
    end
    

    Incorrect Example:

    always @(*) begin
      result <= a + b;  /* Non-blocking assignment in combinational logic */
    end
    
  • Keep the Clock Domain Clean: Ensure that logic within one clock domain does not inadvertently interact with another clock domain. Use appropriate synchronizers and clock domain crossing techniques to prevent metastability.

    Example of Clock Domain Crossing:

    always @(posedge clk1 or posedge reset) begin
      if (reset)
        sync_reg <= 0;
      else
        sync_reg <= async_signal;
    end
    
    always @(posedge clk2) begin
      sync_output <= sync_reg;
    end
    
  • Use Descriptive Signal Names: Avoid generic names like temp, signal1, etc. Choose meaningful signal names that clearly indicate the function and purpose of the signal.

    Correct Example:

    reg [7:0] data_in;   /* Clear and descriptive */
    reg [7:0] data_out;  /* Output of the data */
    

    Incorrect Example:

    reg [7:0] temp;   /* Ambiguous and unclear */
    reg [7:0] sig1;   /* Non-descriptive */
    
  • Follow a Consistent Reset Strategy: Always ensure that reset behavior is consistent across the design. Use synchronous or asynchronous resets depending on the design requirements, and clearly document the reset behavior.

    Correct Example (Synchronous Reset):

    always @(posedge clk) begin
      if (reset)
        data_reg <= 0;
      else
        data_reg <= next_data;
    end
    

    Incorrect Example:

    always @(posedge clk or posedge reset) begin
      if (reset)
        data_reg <= 0;
      else
        data_reg = next_data;  /* Incorrect use of blocking assignment */
    end
    
  • Document RTL Code Clearly: Each module should include a comment block explaining its functionality, inputs, and outputs. Key design choices, such as pipeline stages or timing constraints, should be documented as well.

RTL Design Examples#

Correct Example (Sequential Logic with Non-blocking Assignments):

module counter (
    input  wire clk,
    input  wire reset,
    output reg  [3:0] count
);

always @(posedge clk or posedge reset) begin
  if (reset)
    count <= 0;
  else
    count <= count + 1;
end

endmodule

Incorrect Example (Blocking Assignment in Sequential Logic):

module counter (
    input  wire clk,
    input  wire reset,
    output reg  [3:0] count
);

always @(posedge clk or posedge reset) begin
  if (reset)
    count = 0;  /* Incorrect use of blocking assignment */
  else
    count = count + 1;
end

endmodule

General Guidelines#

  • Use non-blocking assignments (`<=`) for sequential logic inside clocked processes.

  • Use blocking assignments (`=`) for combinational logic.

  • Ensure proper clock domain crossings using synchronizers.

  • Name signals descriptively to improve code readability and maintainability.

  • Keep reset strategy consistent across the design.

  • Document modules and key decisions within the RTL code.