Matter AI | Code Reviewer Documentation home pagelight logodark logo
  • Contact
  • Github
  • Sign in
  • Sign in
  • Documentation
  • Blog
  • Discord
  • Github
  • Introduction
    • What is Matter AI?
    Getting Started
    • QuickStart
    Product
    • Security Analysis
    • Code Quality
    • Agentic Chat
    • RuleSets
    • Memories
    • Analytics
    • Command List
    • Configurations
    Patterns
    • Languages
      • Supported Languages
      • Python
      • Java
      • JavaScript
      • TypeScript
      • Node.js
      • React
      • Fastify
      • Next.js
      • Terraform
      • C#
      • C++
      • C
      • Go
      • Rust
      • Swift
      • React Native
      • Spring Boot
      • Kotlin
      • Flutter
      • Ruby
      • PHP
      • Scala
      • Perl
      • R
      • Dart
      • Elixir
      • Erlang
      • Haskell
      • Lua
      • Julia
      • Clojure
      • Groovy
      • Fortran
      • COBOL
      • Pascal
      • Assembly
      • Bash
      • PowerShell
      • SQL
      • PL/SQL
      • T-SQL
      • MATLAB
      • Objective-C
      • VBA
      • ABAP
      • Apex
      • Apache Camel
      • Crystal
      • D
      • Delphi
      • Elm
      • F#
      • Hack
      • Lisp
      • OCaml
      • Prolog
      • Racket
      • Scheme
      • Solidity
      • Verilog
      • VHDL
      • Zig
      • MongoDB
      • ClickHouse
      • MySQL
      • GraphQL
      • Redis
      • Cassandra
      • Elasticsearch
    • Security
    • Performance
    Integrations
    • Code Repositories
    • Team Messengers
    • Ticketing
    Enterprise
    • Enterprise Deployment Overview
    • Enterprise Configurations
    • Observability and Fallbacks
    • Create Your Own GitHub App
    • Self-Hosting Options
    • RBAC
    Patterns
    Languages

    Verilog

    Verilog is a hardware description language (HDL) used to model electronic systems. It is most commonly used in the design, verification, and implementation of digital logic chips at the register-transfer level of abstraction.

    Verilog, as a hardware description language, has several common anti-patterns that can lead to simulation-synthesis mismatches, timing issues, and hard-to-debug hardware designs. Here are the most important anti-patterns to avoid when writing Verilog code.

    // Anti-pattern: Using blocking assignments in sequential logic
    module counter_bad(input clk, input reset, output reg [3:0] count);
      always @(posedge clk or posedge reset) begin
        if (reset) begin
          count = 0;  // Blocking assignment
        end else begin
          count = count + 1;  // Blocking assignment
        end
      end
    endmodule
    
    // Better approach: Use non-blocking assignments for sequential logic
    module counter_good(input clk, input reset, output reg [3:0] count);
      always @(posedge clk or posedge reset) begin
        if (reset) begin
          count <= 0;  // Non-blocking assignment
        end else begin
          count <= count + 1;  // Non-blocking assignment
        end
      end
    endmodule

    Always use non-blocking assignments (<=) for sequential logic within an always @(posedge clk) block. Using blocking assignments (=) in sequential logic can lead to race conditions and simulation-synthesis mismatches.

    // Anti-pattern: Using non-blocking assignments in combinational logic
    module mux_bad(input a, input b, input sel, output reg y);
      always @(*) begin
        if (sel) begin
          y <= a;  // Non-blocking assignment
        end else begin
          y <= b;  // Non-blocking assignment
        end
      end
    endmodule
    
    // Better approach: Use blocking assignments for combinational logic
    module mux_good(input a, input b, input sel, output reg y);
      always @(*) begin
        if (sel) begin
          y = a;  // Blocking assignment
        end else begin
          y = b;  // Blocking assignment
        end
      end
    endmodule

    Use blocking assignments (=) for combinational logic within an always @(*) block. Using non-blocking assignments (<=) in combinational logic can lead to simulation-synthesis mismatches and incorrect behavior.

    // Anti-pattern: Incomplete sensitivity list
    module alu_bad(input [7:0] a, input [7:0] b, input [1:0] op, output reg [7:0] result);
      always @(a or b) begin  // Missing op in sensitivity list
        case (op)
          2'b00: result = a + b;
          2'b01: result = a - b;
          2'b10: result = a & b;
          2'b11: result = a | b;
        endcase
      end
    endmodule
    
    // Better approach: Use complete sensitivity list or @(*)
    module alu_good(input [7:0] a, input [7:0] b, input [1:0] op, output reg [7:0] result);
      always @(a or b or op) begin  // Complete sensitivity list
        case (op)
          2'b00: result = a + b;
          2'b01: result = a - b;
          2'b10: result = a & b;
          2'b11: result = a | b;
        endcase
      end
    endmodule
    
    // Even better: Use @(*) for automatic sensitivity list
    module alu_best(input [7:0] a, input [7:0] b, input [1:0] op, output reg [7:0] result);
      always @(*) begin  // Automatic sensitivity list
        case (op)
          2'b00: result = a + b;
          2'b01: result = a - b;
          2'b10: result = a & b;
          2'b11: result = a | b;
        endcase
      end
    endmodule

    Always use complete sensitivity lists or the automatic sensitivity list @(*) for combinational logic. Incomplete sensitivity lists can lead to simulation-synthesis mismatches and incorrect behavior.

    // Anti-pattern: Incomplete assignments creating latches
    module fsm_bad(input clk, input reset, input in, output reg out);
      reg [1:0] state, next_state;
      
      always @(*) begin
        case (state)
          2'b00: begin
            if (in) next_state = 2'b01;
            // Missing else clause creates a latch for next_state
          end
          2'b01: begin
            next_state = 2'b10;
            out = 1'b1;  // Missing assignment in other states creates a latch for out
          end
          2'b10: begin
            next_state = 2'b00;
          end
          // Missing default case
        endcase
      end
      
      always @(posedge clk or posedge reset) begin
        if (reset) state <= 2'b00;
        else state <= next_state;
      end
    endmodule
    
    // Better approach: Complete assignments to avoid latches
    module fsm_good(input clk, input reset, input in, output reg out);
      reg [1:0] state, next_state;
      
      always @(*) begin
        // Default assignments to avoid latches
        next_state = state;
        out = 1'b0;
        
        case (state)
          2'b00: begin
            if (in) next_state = 2'b01;
            // else clause not needed due to default assignment
          end
          2'b01: begin
            next_state = 2'b10;
            out = 1'b1;
          end
          2'b10: begin
            next_state = 2'b00;
          end
          default: begin
            next_state = 2'b00;
          end
        endcase
      end
      
      always @(posedge clk or posedge reset) begin
        if (reset) state <= 2'b00;
        else state <= next_state;
      end
    endmodule

    Always provide default assignments to all variables at the beginning of combinational always blocks, and include a default case in case statements. Incomplete assignments can create unintended latches in your design.

    // Anti-pattern: Multiple drivers for the same signal
    module multiple_drivers_bad(input clk, input reset, input en, output reg [7:0] count);
      always @(posedge clk or posedge reset) begin
        if (reset) count <= 8'h00;
        else if (en) count <= count + 1;
      end
      
      always @(posedge clk) begin
        if (count == 8'hFF) count <= 8'h00;  // Second driver for count
      end
    endmodule
    
    // Better approach: Single driver for each signal
    module multiple_drivers_good(input clk, input reset, input en, output reg [7:0] count);
      always @(posedge clk or posedge reset) begin
        if (reset) count <= 8'h00;
        else if (en) begin
          if (count == 8'hFF) count <= 8'h00;
          else count <= count + 1;
        end
      end
    endmodule

    Ensure that each signal has only one driver. Multiple drivers for the same signal can lead to simulation-synthesis mismatches and undefined behavior.

    // Anti-pattern: Mixing blocking and non-blocking assignments
    module mixed_assignments_bad(input clk, input reset, input [7:0] data_in, output reg [7:0] data_out);
      reg [7:0] temp;
      
      always @(posedge clk or posedge reset) begin
        if (reset) begin
          temp <= 8'h00;
          data_out <= 8'h00;
        end else begin
          temp = data_in + 8'h01;  // Blocking assignment
          data_out <= temp;  // Non-blocking assignment
        end
      end
    endmodule
    
    // Better approach: Consistent assignment types
    module mixed_assignments_good(input clk, input reset, input [7:0] data_in, output reg [7:0] data_out);
      reg [7:0] temp;
      
      always @(posedge clk or posedge reset) begin
        if (reset) begin
          temp <= 8'h00;
          data_out <= 8'h00;
        end else begin
          temp <= data_in + 8'h01;  // Non-blocking assignment
          data_out <= temp;  // Non-blocking assignment
        end
      end
    endmodule

    Avoid mixing blocking and non-blocking assignments within the same always block. Use non-blocking assignments consistently for sequential logic and blocking assignments consistently for combinational logic.

    // Anti-pattern: Asynchronous reset release
    module async_reset_release_bad(input clk, input reset, output reg [3:0] count);
      always @(posedge clk or posedge reset) begin
        if (reset) count <= 4'h0;
        else count <= count + 1;
      end
    endmodule
    
    // Better approach: Synchronous reset release
    module sync_reset_release_good(input clk, input reset, output reg [3:0] count);
      reg reset_sync1, reset_sync2;
      
      // Synchronize reset release
      always @(posedge clk or posedge reset) begin
        if (reset) begin
          reset_sync1 <= 1'b1;
          reset_sync2 <= 1'b1;
        end else begin
          reset_sync1 <= 1'b0;
          reset_sync2 <= reset_sync1;
        end
      end
      
      // Use synchronized reset
      always @(posedge clk or posedge reset) begin
        if (reset) count <= 4'h0;
        else if (!reset_sync2) count <= count + 1;
      end
    endmodule

    Synchronize asynchronous reset release to avoid metastability issues. While asynchronous reset assertion is often used for reliable system initialization, the release should be synchronized to the clock to prevent timing violations.

    // Anti-pattern: Combinational loop
    module comb_loop_bad(input a, input b, output reg c);
      reg temp;
      
      always @(*) begin
        temp = a & c;  // c depends on temp, and temp depends on c
        c = temp | b;
      end
    endmodule
    
    // Better approach: Break the combinational loop
    module comb_loop_good(input a, input b, input clk, output reg c);
      reg temp;
      
      // Use a register to break the loop
      always @(posedge clk) begin
        temp <= a & c;
      end
      
      always @(*) begin
        c = temp | b;
      end
    endmodule

    Avoid creating combinational loops in your design. Combinational loops can lead to oscillations, unstable behavior, and synthesis issues. Break loops using registers or redesign your logic.

    // Anti-pattern: Inferring clock gating
    module clock_gate_bad(input clk, input enable, input [7:0] data_in, output reg [7:0] data_out);
      wire gated_clk;
      
      assign gated_clk = clk & enable;  // Inferred clock gating
      
      always @(posedge gated_clk) begin
        data_out <= data_in;
      end
    endmodule
    
    // Better approach: Use enable within the always block
    module clock_gate_good(input clk, input enable, input [7:0] data_in, output reg [7:0] data_out);
      always @(posedge clk) begin
        if (enable) data_out <= data_in;
      end
    endmodule
    
    // Or use proper clock gating cells provided by the technology library
    module clock_gate_best(input clk, input enable, input [7:0] data_in, output reg [7:0] data_out);
      wire gated_clk;
      
      // Instantiate a proper clock gating cell
      CKLNQD1 clock_gate_cell (.CP(clk), .E(enable), .TE(1'b0), .Q(gated_clk));
      
      always @(posedge gated_clk) begin
        data_out <= data_in;
      end
    endmodule

    Avoid inferring clock gating using simple logic gates. Use enable signals within sequential blocks or instantiate proper clock gating cells provided by your technology library.

    // Anti-pattern: Using initial blocks for hardware initialization
    module initial_block_bad(input clk, input [7:0] data_in, output reg [7:0] data_out);
      reg [7:0] memory [0:15];
      
      initial begin
        // Initialize memory
        for (int i = 0; i < 16; i = i + 1) begin
          memory[i] = 8'h00;
        end
        data_out = 8'h00;
      end
      
      always @(posedge clk) begin
        data_out <= memory[data_in[3:0]];
      end
    endmodule
    
    // Better approach: Use reset for initialization
    module initial_block_good(input clk, input reset, input [7:0] data_in, output reg [7:0] data_out);
      reg [7:0] memory [0:15];
      integer i;
      
      always @(posedge clk or posedge reset) begin
        if (reset) begin
          // Initialize memory
          for (i = 0; i < 16; i = i + 1) begin
            memory[i] <= 8'h00;
          end
          data_out <= 8'h00;
        end else begin
          data_out <= memory[data_in[3:0]];
        end
      end
    endmodule

    Avoid using initial blocks for hardware initialization, as they are generally not synthesizable for hardware (except for some specific cases like memory initialization). Use reset signals to initialize your design.

    // Anti-pattern: Ignoring clock domain crossing
    module cdc_bad(input clk_a, input clk_b, input [7:0] data_a, output reg [7:0] data_b);
      always @(posedge clk_b) begin
        data_b <= data_a;  // Direct crossing between clock domains
      end
    endmodule
    
    // Better approach: Use proper synchronization
    module cdc_good(input clk_a, input clk_b, input [7:0] data_a, output reg [7:0] data_b);
      reg [7:0] data_sync1, data_sync2;
      
      // Double-flop synchronizer
      always @(posedge clk_b) begin
        data_sync1 <= data_a;
        data_sync2 <= data_sync1;
        data_b <= data_sync2;
      end
    endmodule
    
    // Even better for multi-bit signals: Use handshaking or FIFO
    module cdc_best(input clk_a, input reset_a, input clk_b, input reset_b,
                   input [7:0] data_a, input valid_a, output reg ready_a,
                   output reg [7:0] data_b, output reg valid_b, input ready_b);
      // Simplified handshaking CDC (a complete implementation would be more complex)
      reg valid_a_sync1, valid_a_sync2;
      reg valid_b_toggle;
      reg valid_b_toggle_sync1, valid_b_toggle_sync2;
      reg valid_b_toggle_prev;
      reg [7:0] data_capture;
      
      // Capture data in source domain
      always @(posedge clk_a or posedge reset_a) begin
        if (reset_a) begin
          valid_b_toggle <= 1'b0;
          ready_a <= 1'b1;
          data_capture <= 8'h00;
        end else begin
          if (valid_a && ready_a) begin
            data_capture <= data_a;
            valid_b_toggle <= ~valid_b_toggle;
            ready_a <= 1'b0;
          end else if (valid_b_toggle_sync2 != valid_b_toggle) begin
            ready_a <= 1'b1;
          end
        end
      end
      
      // Synchronize to destination domain
      always @(posedge clk_b or posedge reset_b) begin
        if (reset_b) begin
          valid_a_sync1 <= 1'b0;
          valid_a_sync2 <= 1'b0;
          valid_b_toggle_sync1 <= 1'b0;
          valid_b_toggle_sync2 <= 1'b0;
          valid_b_toggle_prev <= 1'b0;
          valid_b <= 1'b0;
          data_b <= 8'h00;
        end else begin
          valid_a_sync1 <= valid_b_toggle;
          valid_a_sync2 <= valid_a_sync1;
          valid_b_toggle_sync1 <= valid_b_toggle;
          valid_b_toggle_sync2 <= valid_b_toggle_sync1;
          
          if (valid_b_toggle_sync2 != valid_b_toggle_prev && !valid_b) begin
            data_b <= data_capture;
            valid_b <= 1'b1;
            valid_b_toggle_prev <= valid_b_toggle_sync2;
          end else if (valid_b && ready_b) begin
            valid_b <= 1'b0;
          end
        end
      end
    endmodule

    Always use proper synchronization techniques when crossing clock domains. For single-bit signals, use a double-flop synchronizer. For multi-bit signals, use handshaking protocols, gray coding, or asynchronous FIFOs.

    // Anti-pattern: Using delays for hardware timing
    module delay_bad(input clk, input [7:0] data_in, output reg [7:0] data_out);
      always @(posedge clk) begin
        #2 data_out <= data_in;  // Delay is not synthesizable
      end
    endmodule
    
    // Better approach: Let the synthesis tool handle timing
    module delay_good(input clk, input [7:0] data_in, output reg [7:0] data_out);
      always @(posedge clk) begin
        data_out <= data_in;
      end
    endmodule

    Avoid using delays (#) in synthesizable code. Delays are for simulation only and are ignored during synthesis. Let the synthesis tool handle timing based on your timing constraints.

    // Anti-pattern: Code that generates tool warnings
    module warning_generator(input clk, input reset, input [7:0] data, output reg valid);
      always @(posedge clk or posedge reset) begin
        if (reset) valid <= 1'b0;
        else if (data == 8'hFF) valid <= 1'b1;
        // Warning: valid is not assigned in all branches
      end
    endmodule
    
    // Better approach: Fix the issues causing warnings
    module warning_free(input clk, input reset, input [7:0] data, output reg valid);
      always @(posedge clk or posedge reset) begin
        if (reset) valid <= 1'b0;
        else if (data == 8'hFF) valid <= 1'b1;
        else valid <= valid;  // Explicitly maintain current value
      end
    endmodule

    Don’t ignore warnings from your synthesis and simulation tools. Warnings often indicate potential issues in your design that could lead to unexpected behavior. Fix the issues causing warnings or document why they can be safely ignored.

    // Anti-pattern: Hardcoded constants
    module hardcoded_bad(input clk, input reset, output reg [3:0] count);
      always @(posedge clk or posedge reset) begin
        if (reset) count <= 4'h0;
        else if (count == 4'h9) count <= 4'h0;
        else count <= count + 1;
      end
    endmodule
    
    // Better approach: Use parameters for constants
    module parameterized_good #(
      parameter WIDTH = 4,
      parameter MAX_COUNT = 9
    )(input clk, input reset, output reg [WIDTH-1:0] count);
      always @(posedge clk or posedge reset) begin
        if (reset) count <= {WIDTH{1'b0}};
        else if (count == MAX_COUNT) count <= {WIDTH{1'b0}};
        else count <= count + 1'b1;
      end
    endmodule

    Use parameters for constants in your design. This makes your code more maintainable, reusable, and easier to modify. Parameters can be overridden during module instantiation, allowing for flexible designs.

    // Anti-pattern: Positional port connections
    module top_bad();
      wire clk, reset, enable;
      wire [7:0] data_in, data_out;
      
      // Positional port connections are error-prone
      counter counter_inst(clk, reset, enable, data_in, data_out);
    endmodule
    
    // Better approach: Use named port connections
    module top_good();
      wire clk, reset, enable;
      wire [7:0] data_in, data_out;
      
      // Named port connections are clearer and less error-prone
      counter counter_inst(
        .clk(clk),
        .reset(reset),
        .enable(enable),
        .data_in(data_in),
        .data_out(data_out)
      );
    endmodule

    Use named port connections when instantiating modules. Named connections are clearer, less error-prone, and allow for port reordering without breaking your design.

    // Anti-pattern: Duplicated code for similar structures
    module ripple_carry_bad(input [3:0] a, input [3:0] b, input cin, output [3:0] sum, output cout);
      wire c1, c2, c3;
      
      full_adder fa0(.a(a[0]), .b(b[0]), .cin(cin), .sum(sum[0]), .cout(c1));
      full_adder fa1(.a(a[1]), .b(b[1]), .cin(c1), .sum(sum[1]), .cout(c2));
      full_adder fa2(.a(a[2]), .b(b[2]), .cin(c2), .sum(sum[2]), .cout(c3));
      full_adder fa3(.a(a[3]), .b(b[3]), .cin(c3), .sum(sum[3]), .cout(cout));
    endmodule
    
    // Better approach: Use generate blocks
    module ripple_carry_good #(
      parameter WIDTH = 4
    )(input [WIDTH-1:0] a, input [WIDTH-1:0] b, input cin, output [WIDTH-1:0] sum, output cout);
      wire [WIDTH:0] c;
      
      assign c[0] = cin;
      assign cout = c[WIDTH];
      
      genvar i;
      generate
        for (i = 0; i < WIDTH; i = i + 1) begin : adder_loop
          full_adder fa(
            .a(a[i]),
            .b(b[i]),
            .cin(c[i]),
            .sum(sum[i]),
            .cout(c[i+1])
          );
        end
      endgenerate
    endmodule

    Use generate blocks for repetitive structures in your design. Generate blocks allow for parameterized, scalable designs and reduce code duplication.

    // Anti-pattern: No assertions for verification
    module fsm_no_assertions(input clk, input reset, input in, output reg out);
      reg [1:0] state, next_state;
      
      // State transition logic
      always @(*) begin
        next_state = state;
        case (state)
          2'b00: if (in) next_state = 2'b01;
          2'b01: next_state = 2'b10;
          2'b10: next_state = 2'b00;
          default: next_state = 2'b00;
        endcase
      end
      
      // Output logic
      always @(*) begin
        case (state)
          2'b01: out = 1'b1;
          default: out = 1'b0;
        endcase
      end
      
      // State register
      always @(posedge clk or posedge reset) begin
        if (reset) state <= 2'b00;
        else state <= next_state;
      end
    endmodule
    
    // Better approach: Use assertions for verification
    module fsm_with_assertions(input clk, input reset, input in, output reg out);
      reg [1:0] state, next_state;
      
      // State transition logic
      always @(*) begin
        next_state = state;
        case (state)
          2'b00: if (in) next_state = 2'b01;
          2'b01: next_state = 2'b10;
          2'b10: next_state = 2'b00;
          default: next_state = 2'b00;
        endcase
      end
      
      // Output logic
      always @(*) begin
        case (state)
          2'b01: out = 1'b1;
          default: out = 1'b0;
        endcase
      end
      
      // State register
      always @(posedge clk or posedge reset) begin
        if (reset) state <= 2'b00;
        else state <= next_state;
      end
      
      // Assertions
      // Check that state is always valid
      property valid_state;
        @(posedge clk) disable iff (reset)
          state inside {2'b00, 2'b01, 2'b10};
      endproperty
      assert property (valid_state) else $error("Invalid state detected");
      
      // Check state transition from state 01
      property state_01_transition;
        @(posedge clk) disable iff (reset)
          (state == 2'b01) |=> (state == 2'b10);
      endproperty
      assert property (state_01_transition) else $error("Invalid transition from state 01");
      
      // Check that output is high only in state 01
      property output_high_only_in_state_01;
        @(posedge clk) disable iff (reset)
          (out == 1'b1) |-> (state == 2'b01);
      endproperty
      assert property (output_high_only_in_state_01) else $error("Output high in wrong state");
    endmodule

    Use assertions to verify the correctness of your design. Assertions can catch bugs early in the design process and serve as documentation for expected behavior.

    SolidityVHDL
    websitexgithublinkedin
    Powered by Mintlify
    Assistant
    Responses are generated using AI and may contain mistakes.