Showing posts with label verilog. Show all posts
Showing posts with label verilog. Show all posts

Sep 28, 2026

VLSI Quiz Hub

VLSI & SoC Design Practice Hub

Select a subject domain below to access specific technical test modules.

Check your basics on Digital Design

All Topics Available

Explore the VLSI & SoC Design Practice Hub

Master your foundations across multiple modules including Verification, Static Timing Analysis (STA), UVM Framework, CDC, Logic Synthesis, and RTL coding tracks.

Sep 25, 2026

Educational Project on Verilog - 4 -bit Multiplier with testbench

About the Author

Welcome to my digital design blog! I share in-depth articles on RTL design, timing analysis, ASIC/FPGA concepts, and interview preparation.

Education Project: 4-Bit Multiplier with Testbench in Verilog

This sample project demonstrates a complete RTL design flow for a 4-bit × 4-bit binary multiplier using Verilog. It includes the design specification, the synthesizable Verilog implementation, a self-checking testbench, and sample simulation results.

📁 Project File Structure:
multiplier_project/
├── spec.md              # Design Specification
├── multiplier_4x4.v     # Synthesizable RTL
├── multiplier_tb.v      # Self-checking Testbench
└── run.tcl              # Icarus Verilog simulation script

1. Design Specification

1.1 Purpose

Design a combinational 4-bit binary multiplier that computes the product of two unsigned 4-bit operands using the partial product and sum approach. The design must be fully combinational, synthesizable, and free of latches.

1.2 Functional Requirements

  • Accept two 4-bit unsigned inputs: A[3:0] and B[3:0].
  • Produce an 8-bit unsigned output: P[7:0] = A × B.
  • Minimum product: 0 × 0 = 0 → P = 8'b00000000.
  • Maximum product: 15 × 15 = 225 → P = 8'b11100001.
  • No clock or reset required (pure combinational).

1.3 Interface Specification

Signal Direction Width Description
A Input 4 First unsigned operand
B Input 4 Second unsigned operand
P Output 8 Product (A × B)

1.4 Design Constraints

  • Synthesizable Verilog-2001 (no initial blocks, no delays in RTL).
  • Use only AND gates and adders for partial product generation.
  • Implement using 16 AND gates for partial products and 4 adder stages.
  • No latches, no multi-driver conflicts.
  • Parameterizable width for easy reuse.

1.5 Algorithm

The multiplication is performed as follows:

Step 1: Generate 16 partial products:
PP[i][j] = A[i] AND B[j]   for i=0..3, j=0..3

Step 2: Arrange partial products in a shifted array:
            PP[3][3] PP[2][3] PP[1][3] PP[0][3]
          PP[3][2] PP[2][2] PP[1][2] PP[0][2]
        PP[3][1] PP[2][1] PP[1][1] PP[0][1]
       PP[3][0] PP[2][0] PP[1][0] PP[0][0]

Step 3: Sum all columns using 4-bit adders with carry propagation.

2. Verilog Design (Synthesizable RTL)

The following module implements the 4-bit multiplier using a parameterized partial-product approach.

// File: multiplier_4x4.v
// Description: 4-bit x 4-bit unsigned multiplier
// Algorithm: Partial product + adder tree

module multiplier_4x4 #(
    parameter DATA_WIDTH = 4
) (
    input  wire [DATA_WIDTH-1:0]   A,
    input  wire [DATA_WIDTH-1:0]   B,
    output wire [2*DATA_WIDTH-1:0] P
);

    // ------------------------------------------------------------------
    // Partial product generation
    // PP[i][j] = A[i] & B[j]
    // ------------------------------------------------------------------
    reg [DATA_WIDTH-1:0] pp_row [0:DATA_WIDTH-1];
    integer i, j;

    always @(*) begin
        for (i = 0; i < DATA_WIDTH; i = i + 1) begin
            for (j = 0; j < DATA_WIDTH; j = j + 1) begin
                pp_row[i][j] = A[i] & B[j];
            end
        end
    end

    // ------------------------------------------------------------------
    // Shift and sum partial product rows
    // Row i is shifted left by i positions
    // ------------------------------------------------------------------
    wire [2*DATA_WIDTH-1:0] shifted_pp [0:DATA_WIDTH-1];

    generate
        genvar row;
        for (row = 0; row < DATA_WIDTH; row = row + 1) begin : gen_shift
            assign shifted_pp[row] = {2*DATA_WIDTH{1'b0}} |
                                   ({(2*DATA_WIDTH - DATA_WIDTH){1'b0}}, pp_row[row]) << row;
        end
    endgenerate

    // ------------------------------------------------------------------
    // Sum all shifted rows
    // ------------------------------------------------------------------
    wire [2*DATA_WIDTH-1:0] sum_row1, sum_row2, sum_row3;

    assign sum_row1 = shifted_pp[0] + shifted_pp[1];
    assign sum_row2 = shifted_pp[2] + shifted_pp[3];
    assign sum_row3 = sum_row1 + sum_row2;

    assign P = sum_row3;

endmodule

Alternative: Simplified Version Using Built-in Operator

For quick verification or when synthesis tools handle multiplication optimization internally, the multiplier can be written as a single line:

module multiplier_simple #(
    parameter DATA_WIDTH = 4
) (
    input  wire [DATA_WIDTH-1:0]   A,
    input  wire [DATA_WIDTH-1:0]   B,
    output wire [2*DATA_WIDTH-1:0] P
);

    assign P = A * B;

endmodule
💡 Note: The explicit partial-product version gives you full control over gate-level implementation and is useful for educational purposes. The built-in * operator lets the synthesis tool optimize the multiplier structure (often using Wallace or Dadda trees).

3. Testbench (Self-Checking)

The testbench applies a series of input vectors, compares the output with the expected result, and reports pass/fail status automatically.

// File: multiplier_tb.v
// Description: Self-checking testbench for 4x4 multiplier

`timescale 1ns / 1ps

module multiplier_tb;

    // Parameters
    localparam DATA_WIDTH = 4;

    // Signals
    reg  [DATA_WIDTH-1:0]   A;
    reg  [DATA_WIDTH-1:0]   B;
    wire [2*DATA_WIDTH-1:0] P;

    // DUT Instantiation
    multiplier_4x4 #(
        .DATA_WIDTH(DATA_WIDTH)
    ) dut (
        .A(A),
        .B(B),
        .P(P)
    );

    // Test vectors: {A, B, Expected_P}
    reg  [2*DATA_WIDTH-1:0] A_vec, B_vec;
    integer i;
    integer num_errors = 0;
    integer num_tests  = 0;

    // Expected results lookup table
    function [2*DATA_WIDTH-1:0] expected_product;
        input [DATA_WIDTH-1:0] a;
        input [DATA_WIDTH-1:0] b;
        begin
            expected_product = a * b;
        end
    endfunction

    // Stimulus generation
    initial begin
        $display("==========================================");
        $display(" 4-Bit Multiplier Testbench");
        $display("==========================================");

        // Test case 1: Zero multiplication
        A = 4'd0; B = 4'd0;
        #10;
        check_result(A, B, "Test 1: 0 x 0");

        // Test case 2: One times one
        A = 4'd1; B = 4'd1;
        #10;
        check_result(A, B, "Test 2: 1 x 1");

        // Test case 3: Maximum value
        A = 4'd15; B = 4'd15;
        #10;
        check_result(A, B, "Test 3: 15 x 15");

        // Test case 4: Mixed values
        A = 4'd7; B = 4'd3;
        #10;
        check_result(A, B, "Test 4: 7 x 3");

        // Test case 5: Identity
        A = 4'd5; B = 4'd1;
        #10;
        check_result(A, B, "Test 5: 5 x 1");

        // Exhaustive sweep: all 16x16 combinations
        $display("\nStarting exhaustive sweep (256 cases)...");
        for (i = 0; i < 16; i = i + 1) begin
            A = i[3:0];
            for (j = 0; j < 16; j = j + 1) begin
                B = j[3:0];
                #5;
                check_result(A, B, "Exhaustive");
            end
        end

        // Summary
        $display("==========================================");
        $display(" Test Summary");
        $display("==========================================");
        $display(" Total Tests : %0d", num_tests);
        $display(" Errors      : %0d", num_errors);
        $display(" Status      : %s",
              (num_errors == 0) ? "PASSED ✔" : "FAILED ✘");
        $display("==========================================");

        if (num_errors == 0)
            $finish(0);
        else
            $finish(1);
    end

    // Task to check result
    task check_result(
        input [DATA_WIDTH-1:0]   a,
        input [DATA_WIDTH-1:0]   b,
        input [$clog2(16*16)-1:0] test_name
    );
        wire [2*DATA_WIDTH-1:0] expected = expected_product(a, b);
        begin
            num_tests = num_tests + 1;
            if (P === expected) begin
                $display(" [%0d] A=%0d B=%0d P=%0d | Expected=%0d | PASS",
                              num_tests, a, b, P, expected);
            end else begin
                num_errors = num_errors + 1;
                $display(" [%0d] A=%0d B=%0d P=%0d | Expected=%0d | FAIL",
                              num_tests, a, b, P, expected);
            end
        end
    endtask

    // Waveform dump
    initial begin
        $dumpfile("multiplier.vcd");
        $dumpvars(0);
    end

endmodule

4. Simulation Results

Sample console output from running the testbench with Icarus Verilog:

==========================================
4-Bit Multiplier Testbench
==========================================
[1] A=0 B=0 P=0 | Expected=0 | PASS
[2] A=1 B=1 P=1 | Expected=1 | PASS
[3] A=15 B=15 P=225 | Expected=225 | PASS
[4] A=7 B=3 P=21 | Expected=21 | PASS
[5] A=5 B=1 P=5 | Expected=5 | PASS

Starting exhaustive sweep (256 cases)...
[6] A=0 B=0 P=0 | Expected=0 | PASS
[7] A=0 B=1 P=0 | Expected=0 | PASS
[8] A=0 B=2 P=0 | Expected=0 | PASS
... (251 more PASS lines) ...
[261] A=15 B=15 P=225 | Expected=225 | PASS

==========================================
Test Summary
==========================================
Total Tests : 261
Errors : 0
Status : PASSED ✔
==========================================

5. Running the Simulation

Using Icarus Verilog

# Compile
iverilog -o multiplier_sim multiplier_4x4.v multiplier_tb.v

# Run simulation
vvp multiplier_sim

# View waveform (optional, with GTKWave)
gtkwave multiplier.vcd

Using Vivado (Xilinx)

# From Vivado Tcl Console
create_project multiplier_proj -part xc7a35tcpg236-1
add_files multiplier_4x4.v multiplier_tb.v
set_property top multiplier_tb [current_fileset]
launch_simulation
run all

6. Design Flow Summary

Stage Description Tool
1 Specification Markdown / Word
2 RTL Coding Verilog-2001
3 Functional Simulation Icarus / ModelSim / Vivado
4 Synthesis Yosys / Vivado / Quartus
5 Gate-Level Simulation (Optional) Icarus / ModelSim
6 FPGA Implementation / Tape-out Vivado / Quartus / Synopsys

7. Key Takeaways

  • Start with a clear specification: Define inputs, outputs, functionality, and constraints before writing RTL.
  • Use parameterized modules: Makes the design reusable for different bit widths.
  • Generate partial products explicitly: Educational value in understanding how multipliers work at the gate level.
  • Write self-checking testbenches: Automate verification and avoid manual waveform inspection for basic correctness.
  • Run exhaustive tests: For small designs (4-bit), testing all 256 input combinations is trivial and gives full confidence.
  • Keep RTL clean: No initial blocks, no #delay, no latches in synthesizable code.
  • Document your project: A good specification makes your design easier to review and reuse.

📚 Related Reading

Continue your digital design learning journey:

Table of Contents

Verilog Code for Digital PLL

Digital PLL in Verilog

Digital Phase-Locked Loop (DPLL) in Verilog

A Digital PLL locks the output clock phase to a reference clock using a Phase Detector, a Digital Loop Filter (Integrator), and a Digitally Controlled Oscillator (DCO).

Reference Clock ──► Phase Detector ──► Loop Filter (Accumulator) ──► DCO/VCO ──► Output Clock ▲ │ └──────────────────────────────────────────────────────────┘

1. Architecture Overview

The core components of a digital PLL are:

  • Phase Detector: Measures the phase difference between the reference clock and the feedback clock.
  • Loop Filter: Integrates the phase error over time to generate a stable control word. This acts as a low-pass filter for the digital domain.
  • DCO (VCO): Generates the output clock by accumulating the control word. The output frequency is proportional to the control word value.

2. Complete Verilog Implementation

Note: This implementation uses the reference clock as the timing source for all digital logic. The DCO generates an output clock that is an integer fraction of the reference clock (typically 1/N).

`timescale 1ns / 1ps

/**
 * ============================================================================
 * Digital Phase-Llocked Loop (DPLL)
 * ============================================================================
 * 
 * Structure:
 *   1. Phase Detector: Measures phase error between ref_clk and out_clk
 *   2. Loop Filter:    Digital integrator (accumulator)
 *   3. DCO:            Digitally Controlled Oscillator
 *
 * The DPLL adjusts the output clock's frequency/phase to match the 
 * reference clock, with a fixed division ratio N.
 *
 * ============================================================================
 */

module digital_pll #(
    parameter integer DIV_RATIO  = 2,      // Output freq = Ref freq / DIV_RATIO
    parameter integer ACC_WIDTH  = 16,     // Accumulator width
    parameter integer LOCK_WINDOW = 16     // Cycles to confirm lock
)(
    input  wire                    ref_clk,       // Reference clock
    input  wire                    rst_n,         // Active-low reset
    input  wire                    enable,        // PLL enable
    output reg                     out_clk,       // Output clock
    output wire                    lock,          // Lock indicator
    output wire [ACC_WIDTH-1:0] ctrl_word     // DCO control word (debug)
);

    // =========================================================================
    // Internal Signals
    // =========================================================================
    reg  [ACC_WIDTH-1:0] accumulator;
    reg                  out_clk_reg;
    reg                  lock_flag;

    // Phase detector signals
    reg  ref_clk_d, ref_clk_dd;
    reg  out_clk_d, out_clk_dd;
    wire ref_rise  = ref_clk_d  & ~ref_clk_dd;
    wire out_rise  = out_clk_d  & ~out_clk_dd;

    // Tick counter for phase measurement
    reg  [ACC_WIDTH-1:0] tick_counter;
    reg                  counting;

    // Loop filter (integrator)
    reg  [ACC_WIDTH-1:0] integrator;

    // Lock counter
    reg  [7:0]           lock_counter;

    // =========================================================================
    // 1. Edge Detectors
    // =========================================================================
    always @(posedge ref_clk or negedge rst_n) begin
        if (!rst_n) begin
            ref_clk_d  <= 1'b0;
            ref_clk_dd <= 1'b0;
            out_clk_d  <= 1'b0;
            out_clk_dd <= 1'b0;
        end else begin
            ref_clk_d  <= ref_clk;
            ref_clk_dd <= ref_clk_d;
            out_clk_d  <= out_clk;
            out_clk_dd <= out_clk_d;
        end
    end

    // =========================================================================
    // 2. Phase Detector
    // =========================================================================
    // Measures the time difference between a reference edge and the
    // most recent output edge by counting reference clock cycles.

    always @(posedge ref_clk or negedge rst_n) begin
        if (!rst_n) begin
            tick_counter <= 0;
            counting     <= 1'b0;
        end else if (enable) begin
            if (ref_rise) begin
                // Start counting at reference edge
                tick_counter <= 0;
                counting     <= 1'b1;
            end else if (counting) begin
                if (out_rise) begin
                    // Stop at output edge
                    counting <= 1'b0;
                else begin
                    tick_counter <= tick_counter + 1'b1;
                end
            end
        else begin
            tick_counter <= 0;
            counting     <= 1'b0;
        end
    end

    // =========================================================================
    // 3. Phase Error Calculation
    // =========================================================================
    // Expected ticks per ref cycle = DIV_RATIO
    // Actual measured ticks = tick_counter
    // Error = Expected - Actual

    wire signed [ACC_WIDTH:0] raw_error = 
        $signed({1'b0, DIV_RATIO}) - $signed({1'b0, tick_counter});

    // =========================================================================
    // 4. Digital Loop Filter (Integrator)
    // =========================================================================
    // The integrator accumulates the phase error to produce the control
    // word. This provides the integral action needed for zero steady-state
    // error.

    always @(posedge ref_clk or negedge rst_n) begin
        if (!rst_n) begin
            integrator <= 0;
        else if (enable) begin
            // Update integrator with clamping
            wire signed [ACC_WIDTH+1:0] new_int = 
                $signed({1'b0, integrator}) + {1'b0, raw_error};

            if (new_int > (1 << ACC_WIDTH) - 1)
                integrator <= (1 << ACC_WIDTH) - 1;
            else if (new_int < -(1 << ACC_WIDTH))
                integrator <= 0;
            else
                integrator <= (new_int >= 0) ? new_int[ACC_WIDTH-1:0] : 
                                             (0 - (-new_int)[ACC_WIDTH-1:0]);
        else begin
            integrator <= 0;
        end
    end

    assign ctrl_word = integrator;

    // =========================================================================
    // 5. Digitally Controlled Oscillator (DCO)
    // =========================================================================
    // The DCO accumulates the control word on every ref_clk cycle.
    // When the accumulator overflows, the output clock toggles.

    always @(posedge ref_clk or negedge rst_n) begin
        if (!rst_n) begin
            accumulator <= 0;
            out_clk_reg <= 0;
        end else if (enable) begin
            accumulator <= accumulator + ctrl_word;

            // Toggle output on overflow
            if (accumulator + ctrl_word >= (1 << ACC_WIDTH))
                out_clk_reg <= ~out_clk_reg;
            else
                out_clk_reg <= out_clk_reg;
        end
    end

    assign out_clk = out_clk_reg;

    // =========================================================================
    // 6. Lock Detection
    // =========================================================================
    // Lock is declared when the phase error remains small for
    // a consecutive number of cycles.

    always @(posedge ref_clk or negedge rst_n) begin
        if (!rst_n) begin
            lock_counter <= 0;
        else if (enable) begin
            if ($abs(raw_error) <= 2) begin
                if (lock_counter < LOCK_WINDOW)
                    lock_counter <= lock_counter + 1'b1;
            else begin
                lock_counter <= 0;
            end
        else begin
            lock_counter <= 0;
        end
    end

    assign lock = (lock_counter == LOCK_WINDOW);

endmodule
    

3. Testbench


`timescale 1ns / 1ps

module digital_pll_tb;

    // Parameters
    parameter REF_PERIOD = 10;  // 100 MHz reference
    parameter DIV_RATIO  = 2;   // Output = 50 MHz

    // Signals
    reg  ref_clk;
    reg  rst_n;
    reg  enable;
    wire out_clk;
    wire lock;
    wire [15:0] ctrl_word;

    // Instantiate DUT
    digital_pll #(
        .DIV_RATIO (DIV_RATIO),
        .ACC_WIDTH (16),
        .LOCK_WINDOW(16)
    ) dut (
        .ref_clk   (ref_clk),
        .rst_n     (rst_n),
        .enable    (enable),
        .out_clk   (out_clk),
        .lock      (lock),
        .ctrl_word (ctrl_word)
    );

    // Reference Clock Generation
    initial begin
        ref_clk = 0;
        forever #(REF_PERIOD/2) ref_clk = ~ref_clk;
    end

    // Stimulus
    initial begin
        rst_n = 0;
        enable = 0;

        // Reset
        repeat (5) @(posedge ref_clk);
        rst_n = 1;

        // Enable PLL
        repeat (5) @(posedge ref_clk);
        enable = 1;

        // Run until locked
        wait (lock);
        $display("PLL Locked at time %t", $time);

        // Run for a while after lock
        repeat (100) @(posedge ref_clk);

        // Disable PLL
        enable = 0;
        repeat (10) @(posedge ref_clk);

        $finish;
    end

    // Waveform Dump
    initial begin
        $dumpfile("pll.vcd");
        $dumpvars(0);
    end

endmodule
    

4. Key Parameters Table

Parameter Description Default
DIV_RATIO Division ratio. Output frequency = Reference frequency / DIV_RATIO. 2
ACC_WIDTH Bit width of the accumulator and integrator. Higher values give finer frequency resolution but slower lock time. 16
LOCK_WINDOW Number of consecutive cycles with small phase error required to declare lock. 16

5. Design Considerations

  • Stability: The integrator acts as a loop filter. A higher ACC_WIDTH improves resolution but may slow down the lock time. Ensure the loop bandwidth is well below the Nyquist rate of the reference clock.
  • Lock Time: The time to lock depends on the initial phase error and the integrator gain. For faster locking, you can add a proportional term to the loop filter (PI controller).
  • Area/Power: The accumulator and integrator are the main contributors to area. Keep ACC_WIDTH as small as possible while maintaining sufficient frequency resolution.
  • Simulation vs. Silicon: In silicon, the DCO is often implemented as a series of delay cells (ring oscillator) controlled by the digital word, rather than a simple accumulator. The accumulator-based approach is ideal for simulation and FPGA implementations.
  • Multi-Phase Output: To generate multiple phase-shifted clocks, you can derive additional outputs by sampling the accumulator at different thresholds.

6. References

  • "Digital Phase-Locked Loops: A New Approach" – IEEE Proceedings
  • "All-Digital PLLs for High-Speed SerDes" – Analog Dialogue
  • Standard textbooks on PLL design: Phase-Locked Loops: Design, Simulation, and Application by Gary C. Manatis

Feb 23, 2025

Cyclic Redundancy Check (CRC) Generator - RTL Code



A Cyclic Redundancy Check (CRC) is a popular error-detection technique used in communication protocols and file storage systems to check for data integrity. It involves the use of a polynomial division method to generate a checksum value (CRC code) based on the input data, which can later be used to detect any alterations in the transmitted data.

To implement a CRC generator in RTL (Register-Transfer Level), we need to design a hardware module that computes the CRC value for a given input. Below is an example of how you can write Verilog RTL code for a CRC-16-CCITT-FALSE generator. This CRC uses a 16-bit polynomial, 0x11021, commonly used in communications.

Verilog Code for CRC-16-CCITT-FALSE Generator:

module crc16_ccitt_false(
    input clk,                    // Clock signal
    input reset,                  // Reset signal
    input [7:0] data_in,          // 8-bit input data
    input data_valid,             // Data valid signal to indicate when data_in is valid
    output reg [15:0] crc_out     // 16-bit CRC output
);

    // Polynomial: 0x11021 (x^16 + x^12 + x^5 + 1)
    reg [15:0] crc_reg;            // Internal CRC register

    // CRC shift register calculation
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            // Reset the CRC register to initial value 16'hFFFF
            crc_reg <= 16'hFFFF;
        end
        else if (data_valid) begin
            // Perform CRC calculation for each byte of data
            crc_reg <= crc_reg ^ {8'b0, data_in};  // XOR input data with CRC register
            // Perform polynomial division (shift and XOR with polynomial if MSB is 1)
            for (int i = 0; i < 8; i = i + 1) begin
                if (crc_reg[15] == 1) begin
                    crc_reg = {crc_reg[14:0], 1'b0} ^ 16'h11021;
                end else begin
                    crc_reg = {crc_reg[14:0], 1'b0};
                end
            end
        end
    end

    // Assign the calculated CRC value to the output
    always @(posedge clk or posedge reset) begin
        if (reset)
            crc_out <= 16'hFFFF;  // Reset CRC to 0xFFFF
        else if (data_valid)
            crc_out <= crc_reg;   // Update CRC output when data is valid
    end

endmodule

Explanation of the Code:

  1. Input/Output Ports:

    • clk: Clock input that synchronizes the module.
    • reset: Asynchronous reset signal that initializes the CRC value to 0xFFFF.
    • data_in: 8-bit input data that will be processed in the CRC calculation.
    • data_valid: A signal that indicates when valid data is present on data_in.
    • crc_out: The 16-bit CRC output, which is the result of the CRC calculation.
  2. Internal CRC Register (crc_reg):

    • The internal CRC register holds the intermediate and final CRC value, which is updated as data is processed.
  3. CRC Calculation (Core Logic):

    • The CRC generator uses a polynomial, specifically 0x11021 (x^16 + x^12 + x^5 + 1), to perform the error-checking.
    • On every valid data input (data_valid), the CRC register is XORed with the incoming data byte (data_in).
    • Then, a bit-shifting loop (for loop) is applied where the bits are shifted, and if the most significant bit (MSB) is 1, the polynomial 0x11021 is XORed with the CRC register. This simulates polynomial division.
  4. Reset and Output Assignment:

    • On a reset, the CRC register is initialized to 0xFFFF.
    • After each valid data cycle, the CRC output is updated with the value in the CRC register.

Key Points:

  • Polynomial: The polynomial used here is 0x11021, which is common in CRC-16-CCITT-FALSE. You may modify this polynomial to suit your specific CRC standard (e.g., CRC-16-ANSI, CRC-32, etc.).
  • Data Processing: Data is processed in 8-bit chunks, typical for many data transmission systems.
  • CRC Register Size: In this example, a 16-bit CRC register (crc_reg) is used. Adjust the register size based on the CRC width for your application (e.g., 32 bits for CRC-32).
  • Reset Behavior: The reset signal initializes the CRC to 0xFFFF, which is a common practice for CRC-16-CCITT-FALSE.

Simulation and Testing:

To verify the functionality of this module, you can write a simple testbench to simulate the CRC generator with some input data:

module tb_crc16_ccitt_false;

    reg clk;
    reg reset;
    reg [7:0] data_in;
    reg data_valid;
    wire [15:0] crc_out;

    // Instantiate the CRC16-CCITT-FALSE module
    crc16_ccitt_false crc_gen (
        .clk(clk),
        .reset(reset),
        .data_in(data_in),
        .data_valid(data_valid),
        .crc_out(crc_out)
    );

    // Clock generation
    always begin
        clk = 1'b0;
        #5 clk = 1'b1;
        #5;
    end

    // Test stimulus
    initial begin
        // Initialize signals
        reset = 1;
        data_in = 8'h00;
        data_valid = 0;
        #10;

        reset = 0;
        data_in = 8'hA5;  // Example input data
        data_valid = 1;
        #10;

        data_in = 8'h5A;  // Next byte of data
        #10;

        data_valid = 0;
        #10;

        // End of simulation
        $stop;
    end

endmodule

Conclusion:

This Verilog RTL code implements a basic CRC-16-CCITT-FALSE generator. It takes in 8-bit data chunks and computes the 16-bit CRC checksum using a standard polynomial division algorithm. The code can be adapted to different CRC standards (e.g., CRC-32) by modifying the polynomial and register size as necessary.

May 3, 2021

Tips to start a Academic project from scratch to completion


Many students ask , what are the steps to start a academic project , I understand , many people like to learn many things , for example , bus protocols (AHB,AXI, PCIe,USB , etc ) , there are so many of things to learn if someone wishes to do.

Here are the steps to start :

1. Decide a Topic/Subject

This should be based on your future goal and should be align with your current career.

2. Once project topic is decided, you can start collecting the material, like specification, IEEE papers , collect as much as information you can and sort it out , and start reading on the project topic.

3. DO NOT GO for coding directly.

4. Start writing the design specification , we call it micro-architecture

6. First make the input/output interface, findout what are the signals available.

7. Make sure you get good knowledge on it before writing down the specification.

8. Once your top level block diagram is ready, then start thinking about the sub-blocks.

9. This will keep going on , by writing a design-specification, your 60% job is done !! Yeah !!

10.Once specification is done, you can start writing the code.

11.Once code is dome, you can write down the testing logic also.


After step 11, your project would be 100% complete.. 

Few useful links 

Dec 28, 2016

Verilog Code for Round Robin Algorithm


Round Robin algorithm details :
Round Robin algorithm Verilog code :

What is Round Robin algorithm ?

Round-robin (RR) is one of the algorithms employed by process and network schedulers in computing.As the term is generally used, time slices (also known as time quanta) are assigned to each process in equal portions and in circular order, handling all processes without priority (also known as cyclic executive). Round-robin scheduling is simple, easy to implement, and starvation-free. Round-robin scheduling can also be applied to other scheduling problems, such as data packet scheduling in computer networks. It is an operating system concept.



Below is the diagram.




In the real situation, we can have a modified version of round robin.
Below feature can be include while designing a arbiter using round robin.
  1. If there are no requests,  which ever device/master send request, access will be given in next clock cycle.
  2. For some master, priority can be set. 
  3. Programmable delay to get the access if request is present. 

Below is the block diagram for round robin algorithm with 4 request and 4 grant.




Counter will be controlled by a state machine.




Verilog Code for Round Robin Algorithm : 



Below are the simulation results : 




In the same way, request/grant can be increased to n number.

Ref - https://en.wikipedia.org/wiki/Round-robin_scheduling

Dec 20, 2016

Verilog code square root of a number


Verilog code to calculate the square root of a number ->

------------------Start of Verilog Code --------------------

`timescale 1ns/100ps

module square_root (
  input [31:0] num,
  output reg[31:0] sqr_root,
  output reg sqr_root_integer
 
  );
 
  integer temp;
  reg [31:0] i;
 
  always @(*) begin
   sqr_root = 'b0;
   sqr_root_integer = 1'b0;
   for (i = 0 ; i < (num/2) ; i = i+1 ) begin
      temp = i*i ;
     if (temp  == num) begin
       sqr_root_integer = 1 ;
       sqr_root = i ;
     end
   end
 end
endmodule

module tb;
  reg [31:0] num_in=0;
  reg clk =0;
  wire integer sqrr;
  wire valid;

  always #1 clk = ~clk;
 
  always @(posedge clk) begin
    num_in = num_in +1 ;
  end
 
  square_root DUT (
  .num(num_in),
  .sqr_root_integer(valid),
  .sqr_root(sqrr)
  );
 
  always@(sqrr)
    if(valid)
    $display("Square root of number %d is %d ", num_in , sqrr);

endmodule


-------------------  End of Code -------------------

Simulation result -> 



Thanks for reading my Blog. 

Parameterized Modules in Verilog


How to pass parameter in verilog design from the top module ?

There are different method to do that , when a module is instantiate with different usage, probably width is one of the parameter which may not be same for all instantiation. For example, There is a FIFO design in which depth of the FIFO is parameterized mean FIFO depth can be set from top module. In below design , we see how to do that.

module fifo (
 parameter DEPTH = 10
)
(
input addr[ ] ,
input data [] ,
....
...
...
);

endmodule


Now we want to use this module in design A.

module A (  input  A ,
                   input B
);

// While instantiating the module, parameter can also be passed to fifo module.
fifo  #( .DEPTH(16) ) inst_fifo
(
.addr(),
.data(),
...
...
)

endmodule

in fifo #( .DEPTH(16)) inst_fifo , we can use parameter also.

fifo  #(.DEPTH(FIFO1_DEPTH)) inst_fifo ..

There are different ways to pass the parameter from top module.

Above parameter can be pass to module in this way also.

fifo  #(FIFO1_DEPTH) inst_fifo ..

In this case , if there are more than 1 parameter then order should be followed.

If a module has localparam , then it can not be override.

We can override the default values, either using defparam or by passing a new set of parameters during instantiation. We call this parameter overriding.

A parameter is defined by Verilog as a constant value declared within the module structure. The value can be used to define a set of attributes for the module which can characterize its behavior as well as its physical representation.

Defined inside a module.
Local scope.
Maybe overridden at instantiation time.
If multiple parameters are defined, they must be overridden in the order they were defined. If an overriding value is not specified, the default parameter declaration values are used.

Formal Definition

Parameters are constants typically used to specify the width of variables and time delays.
Simplified Syntax

parameter identifier = constant_expression ,

identifier = constant_expression ;

defparam hierarchical_path = constant_expression ;

This syntax is specified in the IEEE Standard (1800-2009, for example).

defparam is set during compilation time. 

SiteMap